<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>James O&#039;Neill&#039;s Blog</title>
	<atom:link href="http://jamesone111.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://jamesone111.wordpress.com</link>
	<description>PowerShell , Photography, Virtualization and anything else I find worth writing about</description>
	<lastBuildDate>Mon, 06 Feb 2012 14:26:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='jamesone111.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>James O&#039;Neill&#039;s Blog</title>
		<link>http://jamesone111.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://jamesone111.wordpress.com/osd.xml" title="James O&#039;Neill&#039;s Blog" />
	<atom:link rel='hub' href='http://jamesone111.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Customizing PowerShell, Proxy functions and a better Select-String</title>
		<link>http://jamesone111.wordpress.com/2012/02/04/customizing-powershell-proxy-functions-and-a-better-select-string/</link>
		<comments>http://jamesone111.wordpress.com/2012/02/04/customizing-powershell-proxy-functions-and-a-better-select-string/#comments</comments>
		<pubDate>Sat, 04 Feb 2012 21:24:11 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/?p=1799</guid>
		<description><![CDATA[I suspect that even regular PowerShell users don&#8217;t customize their environment much. By co-incidence, in the last few weeks I&#8217;ve made multiple customizations to my systems (my scripts are sync&#8217;d over 3 machines, customize one, customize all). Which has given me multiple things to talk about. My last post was about adding persistent history this [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1799&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I suspect that even regular PowerShell users don&#8217;t customize their environment much. By co-incidence, in the last few weeks I&#8217;ve made multiple customizations to my systems (my scripts are sync&#8217;d over 3 machines, customize one, customize all). Which has given me multiple things to talk about. My last post was about adding persistent history this time I want to look at Proxy Functions …
<p><code><strong>Select-String</strong></code> is, for my money, one of the best things in PowerShell. It looks through piped text or through files for anything which matches a regular expression (or simple text) and reports back what matched and where with all the detail you could ever need.<strong> BUT</strong> It has a couple of things wrong with it: it won&#8217;t do a recursive search for files, and sometimes the information which comes back is <strong>too </strong>detailed. I solved both problems with a function I named &#8220;WhatHas&#8221; which has been part of my profile for ages. I have been using this to search scripts, XML files and saved SQL whenever I need a snippet of code that I can&#8217;t remember or because something needs to be changed and I can&#8217;t be sure I&#8217;ve remembered which files contain it. I use WhatHas dozens (possibly hundreds) of times a week. Because it was a quick hack I didn&#8217;t support every option that <code>Select-string</code> has, so if a code snippet spans lines I have go back to the proper <code><strong>Select-String</strong></code> cmdlet and use its <code>-context</code> option to get the lines either side of the match: more often than not I find myself typing <code>dir -recurse {something} | select-String {options}</code>
<p>A while back I saw a couple of presentations on Proxy functions (there’s <a href="http://blogs.msdn.com/b/powershell/archive/2009/01/04/extending-and-or-modifing-commands-with-proxies.aspx">a good post about them here by Jeffrey Snover</a>): I thought when I saw them that I would need to implement one for real before I could claim to understand them, and after growing tired of jumping back and forth between <code>select-string</code> and WhatHas, I decided it was time to do the job properly creating a proxy function for <code>Select-String</code> and keep whathas as an alias.&nbsp;
<p>There are 3 bits of background knowledge you need for proxy functions.
<ol>
<li><strong>Precedence</strong>. Aliases beat Functions, Functions beat Cmdlets. Cmdlets beat external scripts and programs. A function named Select-String will be called instead of a cmdlet named Select-String &#8211; meaning a function can replace a cmdlet simply by giving it the same name. That is the starting point for a Proxy function.
<li>A command can be invoked as <code>moduleName\CommandName</code>. If I load a function named “Get-Stuff” from my profile.ps1 file for example, it won&#8217;t have an associated module name but if I load it as part of a module, or if “Get-Stuff” is a cmdlet it will have a module name.<br /><code>Get-Command get-stuff | format-list name, modulename</code><br />will show this information You can try <br /><code>&gt; Microsoft.PowerShell.Management\get-childitem</code><br />For yourself. It looks like an invalid file-system path, but remember PowerShell looks for a matching Alias, then a matching Function and a then a matching cmdlet before looking for a file.
<li>Functions can have a <code>process</code> block (which runs for each item passed via the pipeline) a <code>begin</code> block (which runs before the first pass through process, and an <code>end</code> block (which runs after the last item has passed through process.) Cmdlets follow the same structure, although it&#8217;s harder to see.</li>
</ol>
<p>Putting these together<strong> A function named Select-String can call the Select-String cmdlet, but it must call it as Microsoft.PowerShell.Utility\Select-String</strong> or it will just go round in a loop. In some cases, calling it isn’t quite enough and PowerShell V2 delivered the <strong>steppable pipeline</strong> which can take a PowerShell command (or set of commands piped together) and allow us to run its begin block , process block , and end block, under the control of an function. So a Proxy function looks like this :<code><br />Function Select-String { <br />&nbsp; [CmdletBinding()] <br />&nbsp; Param&nbsp; ( <em>Same Parameters as the real Select-String<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Less any I want to prevent people using<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Plus any I want to add <br /></em>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ) <br />&nbsp;&nbsp; Begin { <em>My preliminaries<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Get</em> $steppablePipeline<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $steppablePipeline.begin()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp; <br />Process { <em>My Per-item code against current item ($_ )<br /></em>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $steppablePipeline.Process($_)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
<p>&nbsp;&nbsp;&nbsp;&nbsp; end { $steppablePipeline.End <br /><em>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; My Clean up code </em><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />} </code></p>
<p>What would <strong>really help</strong> would be something produce a function like this template, and fortunately it is built into PowerShell: it does the whole thing in 3 steps: Get the command to be proxied, get the detailed metadata for command and build a Proxy function with the meta data, like this:<br /><code>&nbsp; $cmd=Get-command select-string -CommandType cmdlet <br />&nbsp; $MetaData = New-Object System.Management.Automation.CommandMetaData ($cmd) <br />&nbsp; [System.Management.Automation.ProxyCommand]::create($MetaData) </code>
<p>The last command will output the Proxy function body to the console, I piped the result into Clip.exe and pasted the result into a new definition<br /><code>Function Select-String { }</code> <br />And I had a proxy function. </p>
<p>At this point it didn’t do anything that the original cmdlet doesn’t do but that was a starting point for customizing. <br />The auto-generated parameters are be formatted like this <br /><code>&nbsp; [Parameter(ParameterSetName='Object', Mandatory=$true, ValueFromPipeline=$true)] <br />&nbsp; [AllowNull()] <br />&nbsp; [AllowEmptyString()] <br />&nbsp; [System.Management.Automation.PSObject] <br />&nbsp; ${InputObject},</code> </p>
<p>And I removed some of the line breaks to reduce the screen space they use from 53 lines to about half that. <br />The ProxyCommand creator wraps parameter names in braces just in case something has a space or other breaking character in the name, and I took those out. <br />Then I added two new switch parameters <code>-Recurse</code> and <code>-BareMatches</code>.
<p>Each of the Begin, Process and End blocks in the function contains a <code>try...catch</code> statement, and in the <code>try</code> part of the begin block the creator puts code to check if the <code>-OutBuffer</code> common parameter is set and if it is, over-rides it (why I&#8217;m not sure) &#8211; followed by code to create a steppable pipeline, like this:<br /><code>&nbsp; $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Select-String', <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [System.Management.Automation.CommandTypes]::Cmdlet) <br />&nbsp; $scriptCmd = {&amp; $wrappedCmd @PSBoundParameters } <br />&nbsp; $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin) </code>
<p>I decided it would be easiest to build up a string and make that into the steppable pipeline . In simplified form <br />&nbsp;&nbsp; <code>$wrappedCmd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "Microsoft.PowerShell.Utility\Select-String "&nbsp; <br />&nbsp; $scriptText&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "$wrappedCmd @PSBoundParameters" <br />&nbsp; if ($Recurse)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { $scriptText = "Get-ChildItem @GCI_Params | " + $scriptText } <br />&nbsp; if ($BareMatches)&nbsp; { $scriptText += " | Select-Object –ExpandProperty 'matches' " + <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; " | Select-Object -ExpandProperty 'value'&nbsp;&nbsp; " }&nbsp;&nbsp; <br />&nbsp; $scriptCmd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = [scriptblock]::Create($scriptText)&nbsp;&nbsp; <br />&nbsp; $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)</code>
<p><code>&amp; commandObject</code> works in a scriptblock: the “&amp;” sign says&nbsp; “run <em>this</em>” and if <em>this</em> is a command object that’s just fine: so the generated code has <code>scriptCmd = {&amp; $wrappedCmd @PSBoundParameters }</code> where <code><code>$wrappedCmd</code></code>&nbsp; is a command object. <br />but when I first changed the code from using a script block to using a string I put the original object <code>$wrappedCmd </code>inside a string. When the object is inserted into a string, the conversion renders it as the <em>unqualified</em> name of the command – the information about the module is lost, so I produced a script block which would call the function, which would create a script block which would call the function which&#8230; is an effective way to cause a crash.
<p>The script above won&#8217;t quite work on its own because <br />(a) I haven&#8217;t built up the parameters for <code>Get-Childitem. </code>So if <code>-recurse</code> or –<code>barematches </code>are specified I build up a hash table to hold them, using taking the necessary parameters from what ever was passed, and making sure they aren’t passed on to the Select-String Cmdlet when it is called. I also make sure that a file specification is passed for a recursive search it is moved from the path parameter to the include parameter. <br />(b) If <code>-recurse</code> or <code>-barematches</code> get passed to the” real” Select-String cmdlet it will throw a &#8220;<code>parameter cannot be found</code>&#8221; error, so they need to be removed from <code>$psboundParameters. </code></p>
<p><code></code> This means the first part of the block above turns into <br />&nbsp; <code>if ($recurse -or $include -or $exclude) { <br />&nbsp;&nbsp;&nbsp;&nbsp; $GCI_Params = @{} <br />&nbsp;&nbsp;&nbsp;&nbsp; foreach ($key in @("Include","Exclude","Recurse","Path","LiteralPath")) { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ($psboundparameters[$key]) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code><code>$GCI_Params[$key] = $psboundparameters[$key] <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [void]$psboundparameters.Remove($key) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp; } <br />&nbsp;&nbsp;&nbsp;&nbsp; # if Path doesn't seem to be a folder it is probably a file spec <br />&nbsp;&nbsp;&nbsp;&nbsp; # So if recurse is set, set Include to hold file spec and path to hold current directory <br />&nbsp;&nbsp;&nbsp;&nbsp; if ($Recurse -and -not $include -and ((Test-Path -PathType Container $path) -notcontains $true) ) { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $GCI_Params["Include"] = $path <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $GCI_Params["Path"] = $pwd <br />&nbsp;&nbsp;&nbsp;&nbsp; } <br />&nbsp;&nbsp; $scriptText = "Get-ChildItem @GCI_Params | " <br />} <br />else { $scriptText = ""}</p>
<p></code>
<p>And the last part is <br /><code>if ($BareMatches) { <br />&nbsp; $psboundparameters.Remove("BareMatches") <br />&nbsp; $scriptText += " | Select-object -expandproperty 'matches' | Select-Object -ExpandProperty 'value' " <br />} <br /></code><code>$scriptCmd = [scriptblock]::Create($scriptText) <br />$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)</code>
<p>There’s no need for me to add anything to the process or end blocks, so that&#8217;s it &#8211; everything Select-String originally did, plus recursion and returning bare matches.
<p>I’ve put the whole file on skydrive <a href="http://brzuqg.blu.livefilestore.com/y1pyIzjqKNMe91ycmgC7LZoIoLSqPTQR_44n03TVMlCZ1P4ASTF9WwaevJOihgT-n_yS7kJwJUxPOhlTCtNzFJXJQ/Proxy-Select-String.ps1">here</a></p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/uncategorized/'>Uncategorized</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1799/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1799/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1799/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1799/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1799/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1799/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1799/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1799/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1799/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1799/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1799/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1799/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1799/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1799/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1799&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2012/02/04/customizing-powershell-proxy-functions-and-a-better-select-string/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>
	</item>
		<item>
		<title>Adding Persistent history to PowerShell</title>
		<link>http://jamesone111.wordpress.com/2012/01/28/adding-persistent-history-to-powershell/</link>
		<comments>http://jamesone111.wordpress.com/2012/01/28/adding-persistent-history-to-powershell/#comments</comments>
		<pubDate>Sat, 28 Jan 2012 19:19:37 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/?p=1795</guid>
		<description><![CDATA[The Doctor: “You’re not are you? Tell me you’re not Archaeologists” River Song: “Got a problem with Archaeologists ?”The Doctor: “I’m a time traveller. I point and laugh at Archaeologists” I’ve said to several people that my opinion of Linux has changed since I left Microsoft: after all I took a job with Microsoft because [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1795&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><em>The Doctor: “You’re not are you? Tell me you’re not Archaeologists” <br />River Song: “Got a problem with Archaeologists ?”<br />The Doctor: “I’m a time traveller. I point and laugh at Archaeologists”</em></p>
<p>I’ve said to several people that my opinion of Linux has changed since I left Microsoft: after all I took a job with Microsoft because I rated their products and stayed there 10 years, I didn’t have much knowledge of Linux at the start of that stay and had no call to develop any during it, so my views I had was based on ignorance and supposition. After months of dealing with it on a daily basis I know how wrong I was. In reality Linux is uglier, more dis-functional and, frankly, retarded than I ever imagined it could be. Neither of our Linux advocates suggest it should be used anywhere but servers (just as well they both have iPhones and Xboxes which are about as far from the Open source ideal as it’s possible to go). But compare piping or tab expansion in PowerShell and Bash and you’re left in no doubt which one was designed 20 years ago. “You can only pipe text ? Really ? How … <em>quaint”. </em></p>
<p>One of guys was trying to do something with Exchange from the command-line and threw down a gauntlet. <br />“<strong>If PowerShell’s so bloody good why hasn’t it got persistent history”</strong> <br />OK. This is something which Bash has got going for it. How much work would it take to fix this ? Being PowerShell the answer is “a few minutes”. Actually the answer is “a lot less time than it takes to write a blog post about it”</p>
<p>First a little side track various people I know have a PowerShell prompt which looks like <br /><code>[123]&nbsp; PS C:\users\Fred&gt;</code><br />Where 123 was the<strong> history ID.</strong> Type <code>H</code> (or <code>history</code>, or <code>Get-History</code>) and PowerShell shows you the previous commands, with their history ID, the command <code>Invoke-History &lt;id&gt;</code> (or <code>ihy</code> for short) runs the command. <br />I’d used PowerShell for ages before I discovered typing #&lt;id&gt;[Tab] inserts the history item into the command line. I kept saying “I’ll do that one day”, and like so many things I didn’t get round to it. <br />I already use the history ID I have this function in my profile<br /><code><span style="color:#00008b;">Function</span> <span style="color:#8a2be2;">HowLong</span> <span style="color:#000000;">{</span><br /><span style="color:#006400;">&nbsp;&nbsp; &lt;# .Synopsis Returns the time taken to run a command <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Description By default returns the time taken to run the last command <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#006400;">.Parameter ID The history ID of an earlier item. <br />&nbsp;&nbsp; #&gt;</span><br /><span style="color:#00008b;">&nbsp;&nbsp; param</span>&nbsp; <span style="color:#000000;">(</span> <span style="color:#a9a9a9;">[</span><span style="color:#00bfff;">Parameter</span><span style="color:#000000;">(</span><span style="color:#000000;">ValueFromPipeLine</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#ff4500;">$id</span> <span style="color:#a9a9a9;">=</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$MyInvocation</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">HistoryId</span> <span style="color:#a9a9a9;">-</span><span style="color:#800080;">1</span><span style="color:#000000;">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;&nbsp;&nbsp; <span style="color:#000000;">)</span><br /><span style="color:#00008b;">&nbsp; process</span> <span style="color:#000000;">{</span>&nbsp; <span style="color:#00008b;">foreach</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$i</span> <span style="color:#00008b;">in</span> <span style="color:#ff4500;">$id</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span> <br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (</span><span style="color:#0000ff;">get-history</span> <span style="color:#ff4500;">$i</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">endexecutiontime</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">subtract</span><span style="color:#000000;">(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#000000;">(</span><span style="color:#0000ff;">get-history</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$i</span><span style="color:#000000;">)</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">startexecutiontime</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">totalseconds</span><br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span> <br /><span style="color:#000000;">}</span><br /></code>Once you know <strong>$MyInvocation.HistoryID gives the ID of the current item,</strong> it is easy to change the Prompt function to return something which contains it. </p>
<p>At the moment I find I’m jumping back and forth between PowerShell V2, and the CTP of V3 on my laptop <br />(and I can run PowerShell –Version 2 to launch a V2 version if I see something which I want to check between versions). <br />So<strong> I finally decided I would change the prompt function. </strong>This happened about the time I got the <strong>“why doesn’t the history get saved” </strong>question. Hmmm. Working with history in the Prompt function. Tick, tick, tick.&nbsp; [Side track 2 In PowerShell the prompt isn’t a constant, it is the result of a function.&nbsp; To see the function use the command type function:prompt] <br />So here is the prompt function I now have in my profile. <br /><code><span style="color:#00008b;">Function</span> <span style="color:#8a2be2;">prompt</span> <span style="color:#000000;">{</span><br /><span style="color:#ff4500;">&nbsp; $hid</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$myinvocation</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">historyID</span><br /><span style="color:#00008b;">&nbsp; if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$hid</span> <span style="color:#a9a9a9;">-gt</span> <span style="color:#800080;">1</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span><span style="color:#0000ff;">get-history</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$myinvocation</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">historyID</span> <span style="color:#a9a9a9;">-</span><span style="color:#800080;">1</span> <span style="color:#000000;">)</span> <span style="color:#a9a9a9;">|</span> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#0000ff;">convertto-csv</span> <span style="color:#a9a9a9;">|</span> <span style="color:#0000ff;">Select</span> <span style="color:#000080;">-last</span> <span style="color:#800080;">1</span> <span style="color:#a9a9a9;">&gt;&gt;</span> <span style="color:#ff4500;">$logfile<br />&nbsp; </span><span style="color:#000000;">}</span><br /><span style="color:#000000;">&nbsp; $(</span><span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#0000ff;">test-path</span> <span style="color:#8a2be2;">variable:/PSDebugContext</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span> <span style="color:#8b0000;">'[DBG]: '</span> <span style="color:#000000;">}</span> <span style="color:#00008b;">else</span> <span style="color:#000000;">{</span> <span style="color:#8b0000;">''</span> <span style="color:#000000;">}</span><span style="color:#000000;">)</span> <span style="color:#a9a9a9;">+</span>&nbsp;<br />&nbsp;&nbsp;&nbsp; <span style="color:#8b0000;">"#$([math]::abs($hid)) PS$($PSVersionTable.psversion.major) "</span> <span style="color:#a9a9a9;">+ </span><span style="color:#000000;">$(</span><span style="color:#0000ff;">Get-Location</span><span style="color:#000000;">)</span> <span style="color:#a9a9a9;">+</span>&nbsp;<br />&nbsp;&nbsp;&nbsp; <span style="color:#000000;">$(</span><span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$nestedpromptlevel</span> <span style="color:#a9a9a9;">-ge</span> <span style="color:#800080;">1</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span> <span style="color:#8b0000;">'&gt;&gt;'</span> <span style="color:#000000;">}</span><span style="color:#000000;">)</span> <span style="color:#a9a9a9;">+</span> <span style="color:#8b0000;">'&gt; '</span><br /><span style="color:#000000;">}</span></code></p>
<p><code><span style="color:#000000;"></span></code>The first part is new lines are new: get the history ID and if is greater than 1, get the previous history item, convert from an object to CSV format, discard the CSV header and append it to the file named in <code>$logFile</code> (I know I haven’t set it yet)</p>
<p>The second part is lifted from the prompt function found in the default profile, that reads <br /><code>"PS $($executionContext.SessionState.Path.CurrentLocation)$('&gt;' * ($nestedPromptLevel + 1)) "</code><br />It’s actually one line but I’ve split it at the + signs for ease of reading. <br />I put the a # sign and the history ID before “PS” – when PowerShell starts the ID is –1 so I make sure it is the absolute value.<br />After “PS” I put the major version of PowerShell. <br />I’m particularly pleased with the #ID part in the non-ISE version of PowerShell double clicking on #ID selects it. My mouse is usually close enough to my keyboard that the keypad [Enter] key is within reach of my thumb so if I scroll up to look at something I did earlier, one flickity gesture (double-click, thumb enter, right click [tab]) has the command in the current command line. </p>
<p>So now I’m keeping a log, and all I need to do is to load that log my from Profile. PowerShell has an Add-History command and the on-line help talks about reading in the history from a CSV file so that was easy – I decided I would truncate the log when PowerShell started and also ensure that the file had the CSV header so here’s the reading friendly version of what’s in my profile.</p>
<p><code><span style="color:#ff4500;">$MaximumHistoryCount</span> <span style="color:#a9a9a9;">=</span> <span style="color:#800080;">2048</span><br /><span style="color:#ff4500;">$Global:logfile</span> <span style="color:#a9a9a9;">=</span> <span style="color:#8b0000;">"$env:USERPROFILE\Documents\windowsPowershell\log.csv"</span> <br /><span style="color:#ff4500;">$truncateLogLines</span> <span style="color:#a9a9a9;">=</span> <span style="color:#800080;">100</span><br /><span style="color:#ff4500;">$History</span> <span style="color:#a9a9a9;">=</span> <span style="color:#000000;">@(</span><span style="color:#000000;">)</span><br /><span style="color:#ff4500;">$History</span> <span style="color:#a9a9a9;">+=</span> <span style="color:#8b0000;">'#TYPE Microsoft.PowerShell.Commands.HistoryInfo'</span><br /><span style="color:#ff4500;">$History</span> <span style="color:#a9a9a9;">+=</span> <span style="color:#8b0000;">'"Id","CommandLine","ExecutionStatus","StartExecutionTime","EndExecutionTime"'</span><br /><span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#0000ff;">Test-Path</span> <span style="color:#ff4500;">$logfile</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span><span style="color:#ff4500;">$history</span> <span style="color:#a9a9a9;">+=</span> <span style="color:#000000;">(</span><span style="color:#0000ff;">get-content</span> <span style="color:#ff4500;">$LogFile</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">[</span><span style="color:#a9a9a9;">-</span><span style="color:#ff4500;">$truncateLogLines</span><span style="color:#a9a9a9;">..</span><span style="color:#800080;">-1</span><span style="color:#a9a9a9;">]</span> <span style="color:#a9a9a9;">|</span> <span style="color:#0000ff;">where</span> <span style="color:#000000;">{</span><span style="color:#ff4500;">$_</span> <span style="color:#a9a9a9;">-match</span> <span style="color:#8b0000;">'^"\d+"'</span><span style="color:#000000;">}</span> <span style="color:#000000;">}</span><br /><span style="color:#ff4500;">$history</span> <span style="color:#a9a9a9;">&gt;</span> <span style="color:#ff4500;">$logfile</span><br /><span style="color:#ff4500;">$History</span> <span style="color:#a9a9a9;">|</span> <span style="color:#0000ff;">select</span> <span style="color:#000080;">-Unique</span>&nbsp; <span style="color:#a9a9a9;">|<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;<span style="color:#0000ff;">Convertfrom-csv</span> <span style="color:#000080;">-errorAction</span> <span style="color:#8a2be2;">SilentlyContinue</span> <span style="color:#a9a9a9;">|<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;<span style="color:#0000ff;">Add-History</span> <span style="color:#000080;">-errorAction</span> <span style="color:#8a2be2;">SilentlyContinue</span> </code></p>
<p><strong>UPDATE Copying this code into the blog page and splitting the last $history line to fit, something went wrong and the <br />select -unique went astray. Oops.</strong> It’s there because hitting enter doesn’t advance the History count, or run anything but does cause the prompt function to re-run. Now I’ve had to look it again it occurs to me it would be better to have select –unique in the (get-content $logfile) rather in the Add-history section as this would remove duplicates before truncating. </p>
<p>So … increase the history count, from the default of 64 (writing this I found that in V3 ctp 2 the default is 4096). Set a Global variable to be the path to the log file, and make it obvious what the length is I will truncate the log to.<br />Then build an array of strings named history. Put the CSV header information into $history, and if the log file exists put up to the truncate limit of lines into $history as well. Write $history back to the log file and pipe it into add history, hide any lines which won’t parse correctly. Incidentally those who like really long lines of PowerShell could recode all lines with $history in them into one line. So a couple of lines in the prompt function and between 3 and 9 lines in the profile depending on how you write them all in it’s less than a dozen lines. This blog post has taken a good couple of hours, and I don’t the code in 10 to 15 minutes. </p>
<p><a href="http://jamesone111.files.wordpress.com/2012/01/image.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" border="0" alt="image" src="http://jamesone111.files.wordpress.com/2012/01/image_thumb.png?w=600&#038;h=254" width="600" height="254"></a></p>
<p>Oh , and one thing I really like – when I launch PowerShell –Version 2 inside Version 3, it imports the history giving easy access to the commands I just used without needing to cut and paste. </p>
<p>If you’re a Bash user and didn’t storm off in a huff after my initial rudeness I’d like to set a good natured challenge. A non-compiled enhancement to bash I can load automatically which gives it tab expansion on par with PowerShell’s (OK, PowerShell has an unfair advantage completing parameters, so just command names and file names). And in case you wondered about the quote at the top of the post from one of Stephen Moffat’s Dr Who episodes. You see, <strong>“I Know PowerShell. I point and laugh at Bash users.” </strong></p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/uncategorized/'>Uncategorized</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1795/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1795/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1795/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1795/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1795/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1795/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1795/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1795/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1795/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1795/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1795/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1795/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1795/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1795/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1795&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2012/01/28/adding-persistent-history-to-powershell/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>

		<media:content url="http://jamesone111.files.wordpress.com/2012/01/image_thumb.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>
	</item>
		<item>
		<title>Free NetCmdlets</title>
		<link>http://jamesone111.wordpress.com/2011/12/20/free-netcmdlets/</link>
		<comments>http://jamesone111.wordpress.com/2011/12/20/free-netcmdlets/#comments</comments>
		<pubDate>Tue, 20 Dec 2011 21:48:52 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/?p=1791</guid>
		<description><![CDATA[I’ve mentioned the NetCmdlets before. Although not perfect if you spend a lot of your life using PowerShell and various network tools they are a big help. They’ve made a bunch of things which would have been longwinded and painful relatively easy. So here is a mail I have just had from PowerShell inside (aka [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1791&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<h5>I’ve <a href="https://jamesone111.wordpress.com/2011/08/23/enhancing-the-netcmdlets/">mentioned the NetCmdlets before.</a> Although not perfect if you spend a lot of your life using PowerShell and various network tools they are a big help. They’ve made a bunch of things which would have been longwinded and painful relatively easy. So here is a mail I have just had from PowerShell inside (aka /n software) . I don’t normally hold with pasting mails straight into a blog post, but you’ll see why if you read on: if you click the link it asks you to fill in some details and “<em>A member of our sales team will contact you with your FREE </em><a href="http://www.powershellinside.com/powershell/netcmdlets"><em>NetCmdlets Workstation License</em></a><em>. (Limit one per customer.)”</em></h5>
<blockquote><p><a href="http://nsoftware.us1.list-manage.com/track/click?u=62a6ad331ef56f40b64703ca2&amp;id=efe5def7ae&amp;e=4056f37911"><em>A Gift For The Holidays: FREE NetCmdlets Workstation License &#8211; This Week Only, Tell a Friend!</em></a></p>
<p><em>Help us spread some PowerShell cheer! Tweet, blog, post, email, or just tell a friend and you can both <b>receive a completely free workstation license of NetCmdlets!</b></em>
<p><em>NetCmdlets includes powerful cmdlets offering easy access to every major Internet technology, including: SNMP, LDAP, DNS, Syslog, HTTP, WebDav, FTP, SMTP, POP, IMAP, Rexec/RShell, Telnet, SSH, Remoting, and more. Hurry, this offer ends on Christmas day &#8211; Happy Holidays! </em><br />
<table border="0" cellpadding="0">
<tbody>
<tr>
<td>
<p><b><em>NetCmdlets Workstation License:</em></b></p>
</td>
<td>
<p><em><s>$99.00</s> <b>FREE</b></em></p>
</td>
</tr>
<tr>
<td valign="top">
<p><em><b>NetCmdlets Server License:</b><br />* Special Limited Time Offer *</em></p>
</td>
<td valign="top">
<p><em><s>$349.00</s> <b>$199.00</b> </em><a href="http://nsoftware.us1.list-manage1.com/track/click?u=62a6ad331ef56f40b64703ca2&amp;id=c656ba1478&amp;e=4056f37911"><em>[+] Order Now</em></a></p>
</td>
</tr>
</tbody>
</table>
<p><b><em>Hurry, this offer ends on Christmas day &#8211; </em><a href="http://nsoftware.us1.list-manage1.com/track/click?u=62a6ad331ef56f40b64703ca2&amp;id=3354724bf7&amp;e=4056f37911"><em>Get your free license now</em></a><em>!</em></b>
<p>Happy Holidays!</p>
</blockquote>
<p>Or as we say this side of the Pond <strong>Merry Christmas !</strong></p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/uncategorized/'>Uncategorized</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1791/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1791/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1791/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1791/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1791/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1791/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1791/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1791/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1791/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1791/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1791/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1791/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1791/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1791/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1791&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/12/20/free-netcmdlets/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>
	</item>
		<item>
		<title>PowerShell HashTables: Splatting, nesting, driving selections and generally simplifying life</title>
		<link>http://jamesone111.wordpress.com/2011/12/10/powershell-hashtables-splatting-nesting-driving-selections-and-generally-simplifying-life/</link>
		<comments>http://jamesone111.wordpress.com/2011/12/10/powershell-hashtables-splatting-nesting-driving-selections-and-generally-simplifying-life/#comments</comments>
		<pubDate>Sat, 10 Dec 2011 23:43:12 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Powershell]]></category>
		<category><![CDATA[splatting]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/?p=1784</guid>
		<description><![CDATA[Having spent so much of my life working in Microsoft environments where you typed a password to get into your computer and never had to type it again until the next time you had to login / unlock it (however many servers you worked with in between)&#160; I find working in an office with a [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1784&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Having spent so much of my life working in Microsoft environments where you typed a password to get into your computer and never had to type it again until the next time you had to login / unlock it (however many servers you worked with in between)&nbsp; I find working in an office with a bunch of Linux servers but no shared set of accounts to be alternately comical and stupid.&nbsp; <br />Some of our services use Active Directory to provide LDAP authentication so at least I retype <u>the same</u> user name and password over and over: but back as far as the LAN Manager client for DOS, Microsoft network clients tried to transparently negotiate connections using credentials they already had. Internet explorer does the same when connecting to intranet servers. Even in a workgroup if you manually duplicate accounts between machines you’ll get connected automatically. I stopped retyping passwords about the same time as I stopped saving work to floppy disk; I’m baffled that people in the Unix/Linux world tolerate it.<br />Some of our services use a separate LDAP service instead of AD (just to keep me on my toes I’m JamesOne on one, and Joneill on the other) and others again use their own internal accounts database. I might log on to a given box as <em>root</em>, and sign into MySQL as <em>root</em> but the passwords are different. If I go to another box the root password is different again. And so on. <br />Recently we hit a roadblock because one of the team had set up a server with a root password he couldn’t share (because of the other places he’d used it) and he gave me a key file as a work round. <a href="http://jamesone111.wordpress.com/2011/08/23/enhancing-the-netcmdlets/">I’ve talked before</a> about using the <a href="http://www.powershellinside.com/powershell/netcmdlets/"><strong>NetCmdlets</strong></a> to connect run commands on the Linux boxes. And this sent me back to look at how I was using them. I ended up <strong>driving them from Hash Table of Hash Tables</strong>&nbsp; &#8211; something <a href="http://blogs.technet.com/b/heyscriptingguy/archive/2011/12/10/create-a-hash-table-in-powershell-that-contains-hash-tables.aspx">Ed Wilson has recently written about on the “Hey Scripting Guy” blog</a>. </p>
<p>I use the Hash tables for <strong>splatting&nbsp; -</strong> the name, if not the concept, is peculiar to PowerShell. If it’s not familiar, lets say I want to invoke the command</p>
<p><code>connect-ssh –Server "192.168.42.42" -Force –user "root" –AuthMode "publickey" –CertStoreType "pemkeyfile" `<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -CertSubject "*" -certStore="$env:USERPROFILE\documents\secret.priv"</code> </p>
<p>I can create a hash table ” with members Server, Force, Authmode and so on.&nbsp; Normally when we refer to PowerShell variables we want to work with their <em>Values</em> so we prefix the name with the $ sign. Prefixing the name with the @ sign instead turns the members of an object into parameters for a command : like this </p>
<p><code>
<p>$master =@{Server="192.168.42.42"; Force=$True; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user="root"; AuthMode="publickey"; CertStoreType="pemkeyfile";&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CertSubject="*"; certStore="$env:USERPROFILE\documents\secret.priv"}<br />connect-ssh @master</p>
<p></code>
<p>For another server I might logon with conventional user name and password so I might have: </p>
<p><code>
<p>$Spartacus =@{Server="192.168.109.71"; Force=$True; user="root";}</code></p>
<p>and use that hash table as the basis of logging on.&nbsp; If I want to use one of the copy commands I might add two hash tables together – one containing logon information and the other containing the parameters relating to what should be copied – or I might specify these in the normal way in addition to my splatted variable. <br />In <a href="http://jamesone111.wordpress.com/2011/08/23/enhancing-the-netcmdlets/">my original piece</a> about using the <a href="http://www.powershellinside.com/powershell/netcmdlets/">NetCmdlets</a> I showed <code>Invoke-RemoteCommand, Get-RemoteItem, Copy-Remote-Item, Copy-LocalItem</code> and so on: I have modified all of these to<strong> take a hash table as a parameter and use splatting.</strong> I also showed a set-up function named <code>connect-remote</code>: the hash tables are set up when I load the module, but they don’t contain credentials: <code>connect-remote</code> now looks at the hash-table for the connection I want to make and says “Is this fully specified specified to use a certificate, if not does it have credentials ?” If the answer is no to both parts it <strong>prompts for credentials and adds them to the hash table</strong> – in the snippet below <code>$Server</code> contains the hash table, and <code>$user</code> can be a parameter passed to <code>connect-remote</code> or in the Hash table, and if it can&#8217;t be found in either place it is set to the current user name</p>
<p><code><span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#a9a9a9;">-not</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$server</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">AuthMode</span> <span style="color:#a9a9a9;">-or</span> <span style="color:#ff4500;">$server</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">credential</span><span style="color:#000000;">)</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp; $server</span><span style="color:#a9a9a9;">[</span><span style="color:#8b0000;">"credential"</span><span style="color:#a9a9a9;">]</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$Host</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">ui</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">PromptForCredential</span><span style="color:#000000;">(</span><span style="color:#8b0000;">"Login"</span><span style="color:#a9a9a9;">,</span><span style="color:#8b0000;">"Enter Your Details for $ServerName"</span><span style="color:#a9a9a9;">,</span><span style="color:#8b0000;">"$user"</span><span style="color:#a9a9a9;">,</span><span style="color:#8b0000;">""</span><span style="color:#000000;">)</span><br /><span style="color:#000000;">}</span><br /></code>
<p>A global variable set in <code>connect-remote</code> keeps track of which of the hash tables with SSH settings in should be used as the default for <code>Invoke-RemoteCommand, Get-RemoteItem, Copy-Remote-Item, Copy-LocalItem</code> and so on. But it makes sense to have all the hash tables listed somewhere where they can be accessed by name so I have </p>
<p><code>$hosts = @{ master =@{Server="192.168.42.42"; Force=$True; user="root"; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AuthMode="publickey"; CertStoreType="pemkeyfile"; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CertSubject="*"; certStore="$env:USERPROFILE\documents\secret.priv"}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Spartacus =@{Server="192.168.109.71"; Force=$True; user="root";}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Maximus =@{Server="192.168.10.10"; Force=$True; user="joneill";}<br />}</code><code></code><br /></code></p>
<p>In <code>connect-remote,</code> the -<code>server</code> parameter is declared like this&nbsp; </p>
<p><code><span style="color:#ff4500;">&nbsp; $server</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$hosts</span><span style="color:#a9a9a9;">[</span><span style="color:#000000;">(</span><span style="color:#0000ff;">select-item</span> <span style="color:#ff4500;">$hosts</span> <span style="color:#000080;">-message</span> <span style="color:#8b0000;">"Which server do you want to connect to ? "</span> <span style="color:#000080;">-returnkey</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]</span></code> </p>
<p> <code><span style="color:#0000ff;"><font color="#000000">Select-item </font></span></code>is a function I wrote ages ago which takes a hash table and offers the user a choice based of the keys in the hash table and returns either the number of the choice (not very helpful for hash tables) or its name. <code><br /><span style="color:#00008b;">Function</span> <span style="color:#8a2be2;">Select-Item</span><br /><span style="color:#000000;">{</span><span style="color:#a9a9a9;">[</span><span style="color:#00bfff;">CmdletBinding</span><span style="color:#000000;">(</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]</span><br /><span style="color:#00008b;">param</span> <span style="color:#000000;">(</span><span style="color:#a9a9a9;">[</span><span style="color:#00bfff;">parameter</span><span style="color:#000000;">(</span><span style="color:#000000;">ParameterSetName</span><span style="color:#a9a9a9;">=</span><span style="color:#8b0000;">"p1"</span><span style="color:#a9a9a9;">,</span><span style="color:#000000;">Position</span><span style="color:#a9a9a9;">=</span><span style="color:#800080;">0</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]</span><span style="color:#008080;">[String[]]</span><span style="color:#ff4500;">$TextChoices</span><span style="color:#a9a9a9;">,</span><br /><span style="color:#a9a9a9;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [</span><span style="color:#00bfff;">Parameter</span><span style="color:#000000;">(</span><span style="color:#000000;">ParameterSetName</span><span style="color:#a9a9a9;">=</span><span style="color:#8b0000;">"p2"</span><span style="color:#a9a9a9;">,</span><span style="color:#000000;">Position</span><span style="color:#a9a9a9;">=</span><span style="color:#800080;">0</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]</span><span style="color:#008080;">[hashTable]</span><span style="color:#ff4500;">$HashChoices</span><span style="color:#a9a9a9;">,</span> <br /><span style="color:#008080;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [String]</span><span style="color:#ff4500;">$Caption</span><span style="color:#a9a9a9;">=</span><span style="color:#8b0000;">"Please make a selection"</span><span style="color:#a9a9a9;">,</span> <br /><span style="color:#008080;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [String]</span><span style="color:#ff4500;">$Message</span><span style="color:#a9a9a9;">=</span><span style="color:#8b0000;">"Choices are presented below"</span><span style="color:#a9a9a9;">,</span> <br /><span style="color:#008080;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [int]</span><span style="color:#ff4500;">$default</span><span style="color:#a9a9a9;">=</span><span style="color:#800080;">0</span><span style="color:#a9a9a9;">,</span><br /><span style="color:#008080;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Switch]</span><span style="color:#ff4500;">$returnKey</span><br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )</span> <br /><span style="color:#ff4500;">$choicedesc</span> <span style="color:#a9a9a9;">=</span> <span style="color:#0000ff;">New-Object</span> <span style="color:#8a2be2;">System.Collections.ObjectModel.Collection[System.Management.Automation.Host.ChoiceDescription]</span> <br /><span style="color:#00008b;">switch</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$PsCmdlet</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">ParameterSetName</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span>&nbsp;<br /><span style="color:#8b0000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "p1"</span> <span style="color:#000000;">{</span><span style="color:#ff4500;">$TextChoices</span> <span style="color:#a9a9a9;">|</span> <span style="color:#0000ff;">ForEach-Object</span> <span style="color:#000000;">{</span> <span style="color:#ff4500;">$choicedesc</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Add</span><span style="color:#000000;">(</span><span style="color:#000000;">(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#0000ff;">New-Object</span> <span style="color:#8b0000;">"System.Management.Automation.Host.ChoiceDescription"</span> <span style="color:#000080;">-ArgumentList</span> <span style="color:#ff4500;">$_</span> <span style="color:#000000;">)</span><span style="color:#000000;">)</span> <span style="color:#000000;">}</span> <span style="color:#000000;">}</span> <br /><span style="color:#8b0000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "p2"</span> <span style="color:#000000;">{</span><span style="color:#00008b;">foreach</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$key</span> <span style="color:#00008b;">in</span> <span style="color:#ff4500;">$HashChoices</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Keys</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span> <span style="color:#ff4500;">$choicedesc</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Add</span><span style="color:#000000;">(</span><span style="color:#000000;">(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#0000ff;">New-Object</span> <span style="color:#8b0000;">"System.Management.Automation.Host.ChoiceDescription"</span> <span style="color:#000080;">-ArgumentList</span> <span style="color:#ff4500;">$key</span><span style="color:#a9a9a9;">,</span><span style="color:#ff4500;">$HashChoices</span><span style="color:#a9a9a9;">[</span><span style="color:#ff4500;">$key</span><span style="color:#a9a9a9;">]</span> <span style="color:#000000;">)</span><span style="color:#000000;">)</span> <span style="color:#000000;">}</span> <span style="color:#000000;">}</span> <br /><span style="color:#000000;">}</span><br /><span style="color:#00008b;">If</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$returnkey</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span> <span style="color:#ff4500;">$choicedesc</span><span style="color:#a9a9a9;">[</span><span style="color:#ff4500;">$Host</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">ui</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">PromptForChoice</span><span style="color:#000000;">(</span><span style="color:#ff4500;">$caption</span><span style="color:#a9a9a9;">,</span> <span style="color:#ff4500;">$message</span><span style="color:#a9a9a9;">,</span> <span style="color:#ff4500;">$choicedesc</span><span style="color:#a9a9a9;">,</span> <span style="color:#ff4500;">$default</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">label</span> <span style="color:#000000;">}</span><br /><span style="color:#00008b;">else</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000000;">{</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#ff4500;">$Host</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">ui</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">PromptForChoice</span><span style="color:#000000;">(</span><span style="color:#ff4500;">$caption</span><span style="color:#a9a9a9;">,</span> <span style="color:#ff4500;">$message</span><span style="color:#a9a9a9;">,</span> <span style="color:#ff4500;">$choicedesc</span><span style="color:#a9a9a9;">,</span> <span style="color:#ff4500;">$default</span><span style="color:#000000;">)</span> <span style="color:#000000;">}</span><br /><span style="color:#000000;">}</span></code></p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/powershell/'>Powershell</a> Tagged: <a href='http://jamesone111.wordpress.com/tag/splatting/'>splatting</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1784/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1784/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1784/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1784/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1784/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1784/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1784/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1784/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1784/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1784/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1784/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1784/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1784/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1784/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1784&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/12/10/powershell-hashtables-splatting-nesting-driving-selections-and-generally-simplifying-life/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>
	</item>
		<item>
		<title>PowerShell&#8211;full of stringy goodness.</title>
		<link>http://jamesone111.wordpress.com/2011/12/03/powershellfull-of-stringy-goodness/</link>
		<comments>http://jamesone111.wordpress.com/2011/12/03/powershellfull-of-stringy-goodness/#comments</comments>
		<pubDate>Sat, 03 Dec 2011 14:28:02 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Powershell]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/?p=1780</guid>
		<description><![CDATA[I think almost everyone who works with PowerShell learns two things in their first few minutes. (a) Assigning some text to a Variable looks like this $Name =&#160; "James" (b) When you wrap a string in double quotes it expands variables inside it, for example "Hello $Name" will evaluate to Hello James. A little later [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1780&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I think almost everyone who works with PowerShell learns two things in their first few minutes. <br />(a) Assigning some text to a Variable looks like this <code>$Name =&nbsp; "James" </code><br />(b) When you wrap a string in double quotes it expands variables inside it, for example <code>"Hello $Name"</code> will evaluate to <code>Hello James.</code> </p>
<p>A little later we tend to learn that if we want to put a property of a variable in string things get marginally more complex.<br /><code>"The name $Name is $name.length characters long"</code> gives the text <code>the name James is James.length characters long.</code> </p>
<p>To get the length of what is stored in the variable named “name” we need to use <code>"The name $Name is $($name.length) characters long"</code>. This gives <code>the name James is 5 characters long.</code></p>
<p>And most of us also learn that PowerShell can have Multi-line strings, sometimes called Here-Strings. which look like this</p>
<p><code>$HereString=@"<br />Here is a string<br />The string $name made<br />It hasn’t finished yet<br />There’s more<br />OK we’re done<br />"@</code></p>
<p>Here-strings are really useful because they don’t close until they reach “@ at the start of a line, they can contain quotes, newlines and if they use double quotes they too will expand variables. </p>
<p>I should say here that I don’t have any detailed knowledge of how PowerShell’s parser <em>actually</em> deals with strings, but it <em>seems</em> pretty clear that when it hits a $ sign it says “OK I need to work out a value here”. I think using $ to mean “value of” was something PowerShell picked up from another language but I can’t be sure which one it was. My inner Pedant wants to correct people when they say “PowerShell variable names begin with $” <code>$foo</code> means the value that is in <code>foo</code>: the <em>name</em> is foo. The way I understand it, when the parser sees $ inside a string it looks to see what comes next: if it is a sequence of letters it assumes they are the name of variable, which it should insert into the string. If is a “(“ character then it looks for the matching “)” and evaluates the expression inside, like <code>$name.length</code>. Easy. Only this week I found myself saying … <em>these are nothing special … well, we can get much better things than that. </em></p>
<p>I had to create over a dozen XML files: all identical except each one had a different database table name and a subset of the fields in the table – some had just 2 fields others had more than a dozen, the XML went like this. <br /><code>&lt;stuff&gt;<br />&nbsp;&nbsp; &lt;kind1 name=<strong>TableName</strong>&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;field name=<strong>field1</strong>&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;field name=<strong>field2</strong>&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;field name=<strong>field3</strong>&gt;<br />&nbsp;&nbsp; &lt;/kind1&gt;<br />&nbsp;&nbsp; &lt;xmlgumf /&gt;<br />&nbsp;&nbsp; &lt;kind2 name=<strong>TableName</strong>&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;field name=<strong>field1</strong>&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;field name=<strong>field2</strong>&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;field name=<strong>field3</strong>&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;field name=<strong>field3</strong>&gt;<br />&nbsp;&nbsp; &lt;/kind2&gt;<br />&nbsp;&nbsp; &lt;xmlgumf /&gt;<br />&lt;/stuff&gt;</code></p>
<p>Except the real XML was <em>much</em> more complicated. Using the tool which builds the XML file from scratch takes about an hour per file. The XML files then go into another tool which is where the real magic happens. Building a dozen files would be couple of days work, or with the project I’m working on , a very late night. <br />I had a document with the table names and the field lists in them, so <strong>could I automate the creation of these XML files ?<br /></strong>Outside of a string I’d write something like this<br /><code>$fields=”Field1”,”Field2”,”Field3”<br />$fields | foreach -begin {$a=""} -process {$a += [environment]::newline + "&lt;Field name=$_ &gt;"} -end {$a}</p>
<p></code>
<p>Would that second line work in a here-string based on an existing XML file?<strong> How well would this work ?</strong></p>
<p></code>$Table = "TableName"<br />$fields=”Field1”,”Field2”,”Field3”<br />@"<br />&lt;stuff&gt;<br />&nbsp;&nbsp; &lt;kind1 name=$Table&gt;$($fields | foreach -begin {$a=""} -process {$a += [environment]::newline + "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Field name=$_ &gt;"} -end {$a})<br />&nbsp;&nbsp; &lt;/kind1&gt;<br />&nbsp;&nbsp; &lt;xmlgumf /&gt;<br />&nbsp;&nbsp; &lt;kind2 name=$Table&gt;$($fields | foreach -begin {$a=""} -process {$a += [environment]::newline + " &lt;Field name=$_ &gt;"} -end {$a})<br />&nbsp;&nbsp; &lt;/kind2&gt;<br />&nbsp;&nbsp; &lt;xmlgumf /&gt;<br />&lt;/stuff&gt;<br />"@ | out-file "$table.xml” –encoding ascii</code></p>
<p>The simple answer is <strong>it works like a charm. </strong><br />Building the first XML file took an hour using the normal tool to do it from scratch, it then took 5 minutes to convert that file into a template - which to my immense delight worked first time. Producing each additional XML file took 2 minutes. Half an hour in all. That’s 10.5 hours I’ve got to do something else with. And showing it to colleagues their reaction was I had performed serious magic. The kind of magic which lets me disappear early. </p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/powershell/'>Powershell</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1780/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1780/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1780/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1780/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1780/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1780/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1780/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1780/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1780/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1780/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1780/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1780/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1780/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1780/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1780&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/12/03/powershellfull-of-stringy-goodness/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>
	</item>
		<item>
		<title>Maximize the reuse of your PowerShell</title>
		<link>http://jamesone111.wordpress.com/2011/10/24/maximize-the-reuse-of-your-powershell/</link>
		<comments>http://jamesone111.wordpress.com/2011/10/24/maximize-the-reuse-of-your-powershell/#comments</comments>
		<pubDate>Mon, 24 Oct 2011 15:18:18 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Powershell]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/2011/10/24/maximize-the-reuse-of-your-powershell/</guid>
		<description><![CDATA[Last week I was at The Experts Conference in Frankfurt presenting at the PowerShell Deep Dive. My presentation was entitled “Maximize the reuse of your PowerShell”. My PowerShell library for managing Hyper-V has now gone through a total of 100,000 downloads over all its different versions but whether it’s got wide use because of the [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1776&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<table border="0" cellspacing="0" cellpadding="2" width="100%">
<tbody>
<tr>
<td valign="top">Last week I was at The Experts Conference in Frankfurt presenting at the PowerShell Deep Dive. <a href="https://skydrive.live.com/view.aspx?cid=1EFE2682BFBBD817&amp;resid=1EFE2682BFBBD817%212431">My presentation</a> was entitled “Maximize the reuse of your PowerShell”. <br />My PowerShell library for managing Hyper-V has now gone through a total of 100,000 downloads over all its different versions but whether it’s got wide use because of the way I wrote it or in spite of it, I can’t say.&nbsp; Some people whose views I value seem to agree with the ideas I put forward in the talk, so I’m setting them out in this (rather long) post. </td>
<td valign="top"><a href="http://jamesone111.files.wordpress.com/2011/10/image.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" border="0" alt="image" src="http://jamesone111.files.wordpress.com/2011/10/image_thumb.png?w=308&#038;h=142" width="308" height="142"></a></td>
</tr>
</tbody>
</table>
<p>I have never lost my love of Lego. Like Lego,<em>&nbsp;</em><strong>PowerShell succeeds by being a kit of small, general purpose blocks to link together.&nbsp; Not everything we do can extend that kit, but we should aim to do that where possible. </strong>I rediscovered the <a href="http://blogs.msdn.com/b/powershell/archive/2007/03/19/monad-manifesto-the-origin-of-windows-powershell.aspx">Monad Manifesto</a> recently via <a href="http://www.jsnover.com/blog/2011/10/01/monad-manifesto/">a piece Jeffrey Snover about </a>how PowerShell has remained true to the original vision, named Monad. It talks of a model where <em>“Every executable should do a narrow set of functions and complex functions should be composed by pipelining or sequencing executables together”.&nbsp; </em><u>Your work is easier to reuse if it becomes a building block that can be incorporated into more complex solutions;</u> and this certainly isn’t unique to PowerShell.&nbsp;&nbsp;&nbsp;
<p><strong>Functions for re-use, scripts for a single task.</strong> If you a use .PS1 script to carry out a task it is effectively a batch file:&nbsp; it <u>is</u> automating stuff so that’s good, but it isn’t a building block for other work. Once loaded, functions behave like like compiled cmdlets. If you separate parts of a script into functions it should be done with the aim of making those parts easy to reuse and recycle, <u>not</u> simply be to reformat a script into subroutines. <br />If we’re going to write functions how should they look?
<p><strong>Choose names wisely, One task : One Function, there is no &#8220;DoStuffWith&#8221; verb for a reason.<br /></strong>PowerShell cmdlets use names in the form <em>Verb-Noun </em>and it is best to stick to this model; the <code>Get-Verb</code> command will give you a list of the <em>Approved </em>verbs. PowerShell’s enforcement of these standards is limited to raising a warning if you use non-standard names in a module. If your action <u>really</u> isn’t covered by a standard verb, then <a href="http://connect.microsoft.com/PowerShell">log the need for another one on connect</a>; but if you use “Duplicate” when the standard says “Copy”, or “Delete” when the standard says “Remove” it simply makes things more difficult for people who know PowerShell but don’t know your stuff. The same applies to parameter names: try to use the ones people already know. Getting the function name right sets the scope for your work. For my talk I used an example of generating MD5 hashes for files. My assertion was that the MD5 hash <em>belonged to </em>the file, and so command should return a file with an added MD5 hash &#8211; meaning my command should be <code>ADD-MD5</code>.</p>
<p><strong>Output: Use the right Out- and Write- cmdlets</strong> Other speakers at the Deep Dive made the point that output created with <code>Write-Host</code> isn’t truly <em>returned </em>(in the sense that it can be piped or redirected) it is <em>writing on the console screen; </em>so only use <code>Write-Host</code> if you want to <u>prevent output going anywhere else</u>. There are other “write on the screen without returning” cmdlets which might be better: for example when debugging we often want messages that say “starting stage 1” , “starting stage 2” and so on. One way to do this would be to add <code>Write-Host</code> statements and after the code is debugged remove them. A better way is to use <code>Write-Verbose</code> which outputs if you specify a <code>–verbose</code> switch and doesn’t if you don’t. As a side effect you have a quasi-comment in your code which tells you what is happening. The same is true when you use <code>Write-Progress</code> to indicate something is happening in a long running function, (remember to run it with the <code>-completed</code> switch when you have finished otherwise your progress box can remain on screen while something else runs). <code>Write-Debug, Write-Error</code> and <code>Write-Warning</code> are valuable, I try to prevent errors appearing where the code can recover and write a warning when something didn’t go to plan, in a non-fatal way.</p>
<p><strong>Formatting</strong> results can be a thorny issue: you <em>can</em> redirect the results of <code>Format-Table</code> or <code>Format-List</code> to a file, but the output is useless if you want to pipe results into another command – which needs the original object. <br />Some objects can have ugly output: it’s not a crime to have an <code>–asTable</code> switch so output goes through <code>Format-Table</code> at the end of the function or even to produce pretty output by default provided you <strong>ensure that it is possible to get the raw object into the pipe</strong> with a <code>–noFormat</code> or <code>–Raw</code> switch. But it’s <strong>best to create formatting XML</strong> and a lot easier with tools like <a href="http://ezout.start-automating.com/">James Brundage’s E-Z-out.</a></p>
<p><strong>Output with the pipeline in mind.</strong>&nbsp;<u>It’s not enough to just avoid write-host and return some sort of object</u>. I argued that a function should <em><strong>return the richest object that is practical &#8211; </strong></em>my example used <code>Add-Member</code> to take a file object and give it an additional MD5Hash property. I can do anything with the result that I can do with a file and default formatting rules for a file are used (which is usually good)&nbsp; but being the right <u>type</u> need not matter if the object has the right property/properties. For example, this line of PowerShell :<br /><code>&nbsp; Select-String -Path *.ps1 -Pattern "Select-String"</code><br />looks at all the .PS1 files in the current folder and where it finds the text&nbsp; “<code>Select-String</code>”&nbsp; it outputs a <code>MatchInfo</code> object with the properties: <code>.Context, .Filename, .IgnoreCase, .Line, .LineNumber, .Matches, .Path </code>and<code> .Pattern.</code> A<code> </code>Cmdlet like <code>Copy-Item</code> has no idea about <code>MatchInfo</code> objects, but if an object piped in has a <code>.path</code> property, it will knows what it is being asked to work on. If <code>Matchinfo</code> objects named this property “NameOfMatchingFile” it just would not work.&nbsp; </p>
<p><strong>Think about pipelined input.</strong> All it takes to tell PowerShell that a parameter should come from the pipeline is prefixing its declaration with<br /><code>&nbsp; [parameter(ValueFromPipeLine= $true)]<font face="Verdana"> </font></code><br />If you find that you are using your new function like this<br /><code>&nbsp; Get-thing | ForEach {Verb-Thing –thing $_}</code> <br />It’s telling you that <code>-thing</code> should take pipeline values. </p>
<p>The <u>pipeline can supply multiple items</u> , so a function may need to be split into <code>Begin{}</code> ,&nbsp; <code>process{}</code> and <code>End {}</code> blocks. (If you don’t specify these the whole function body is treated as an end block and only the last item passed is processed). Eventually the realization dawns that if the example above works, it should be possible have two lines:<br />&nbsp; <code>$t = Get-thing <br />Verb-Thing –thing $t</code>&nbsp;<br />So parameters need to be able to handle arrays – something I’ll come back to further down. </p>
<p>You can do the same thing that <code>Copy-Item</code> was shown doing above: I have another function which is a wrapper for <code>Select-String,</code> its parameters include:<br /><code>&nbsp; [Parameter(ValueFromPipeLine=$true,Mandatory=$true)] <br />&nbsp; $Pattern, <br />&nbsp; [parameter(ValueFromPipelineByPropertyName = $true)][Alias('Fullname','Path')]<br />&nbsp; $Include=@("*.ps1","*.js","*.sql")</code><br />If the function gets passed a string via the pipeline it is the value for the <code>-pattern</code> parameter. If it gets an object containing a property named “Include”, “Fullname” or “path” that <em>property</em> becomes the value for the <code>–include</code> parameter. </p>
<p>Sometimes a function needs to output to a destination based on input: so you can check to see if a parameter is a script block and evaluate it if it is.&nbsp; </p>
<p><strong>Don’t require users to know syntax for things inside your function.</strong> If you are going to write code to do one job and never reuse it then you don’t need to be flexible.<strong> If the code is to be reused, <strong>you need to do a little extra work so users don’t have to. </strong></strong>For example: if something you use needs a fully qualified path to a file, then the function should use <code>Resolve-Path</code> to avoid an error when the user supplies the name of a file in the current directory. <code>Resolve-Path</code> is quite content to resolve multiple items so replacing&nbsp;&nbsp;&nbsp; <br /><code>&nbsp; Do_stuff_with $path <br /></code>with<br /><code>&nbsp; Resolve-Path $path | for-each {Do stuff with $_ }<br /></code>Delivers, at a stroke, support for Wildcards, multiple items passed in $path and relative names . <br />Another example is with WMI, where syntax is based on SQL so the wildcard is “%”, not “*”. Users will assume the wildcard is *. In this case do you say:<br />(a) Users should learn to use “%”&nbsp;&nbsp;&nbsp; <br />(b) My&nbsp; function should include&nbsp;&nbsp; <code>$parameter = $parameter -Replace "*","%"</code>&nbsp; <br />For my demo I showed a function I have named “<code>Get-IndexedItem</code>” which finds things using the Windows index. I wanted to find my best underwater photos- they are tagged “portfolio” and are the only photos I shoot with a Canon camera. My function lets me type<br /><code>&nbsp; Get-IndexedItem cameramaker=can*,tag=portfolio </code><br />Inside the function the search system needs a where condition of <br />&nbsp; “<code>System.Photo.Cameramanufacturer LIKE 'can%'&nbsp; AND System.Keywords = 'portfolio'</code>” <br />Some tools would require me to type the filtering condition in this form, but I don’t want to remember what prefixes are needed and whether the names are “<code>camera Maker</code>” or “<code>camera Manufacturer</code>” and “<code>keyword</code>”, “<code>keywords</code>” or “<code>tag</code>”. Half the time I’ll forget to wrap things in single quotes, or use “*” as I wild card because I forgot this was SQL. And if I have multiple search terms why shouldn’t they be a list not “A and b and C” (there is a write-up coming for how I did this processing. ).</p>
<p><strong>Set sensible defaults.</strong>&nbsp; The talk before mine highlighted some examples of “bad” coding, and showed a function which accepted a computer name. Every time the user runs the command they must specify the computer. Is it valid to assume that most of the time the command will run against the current computer? If so the parameter should default to that. If the tool deals with files is it valid to assume “all files in the current directory” – if the command is delete, probably not, if it displays some aspect of the files, it probably can. <br /><strong>Constants could be Parameter defaults </strong>With computer name example you might write a function which <u>only</u> ran against the current computer. Obviously it is more useful if the computer name is a parameter (with a default) not a constant. In a surprising number of a cases, something you create to do a specific task can carry out a generic task if you change a fixed value in your code into a parameter, which defaults to the former fixed value. </p>
<p><strong>Be flexible about parameter types and other validation </strong>This is a variation on not making the user understand the internals of your function and I have talked about it before, in particular the dangers of people who are trained systems programmers applying the techniques in PowerShell they would use in something like C#: in those languages a function declaration might look like:<br /><code>&nbsp; single Circumference(single radius) {} </code><br />which says <em>Circumference takes a parameter which must have been declared to be a single precision real number and returns a single precision real number.</em> Writing<br /><code>&nbsp;&nbsp; c = Circumference("Hello"); <br /></code>or<code>&nbsp; c = Circumference("42"); </code><br />will cause the compiler to give a “type mismatch” error – &#8220;Hello&#8221; and &#8220;42&#8243; are strings, not single precision real numbers . Similarly <br /><code>System.io.fileinfo f = Circumference(42); </code><br />Is a type mismatch: <code>f</code> is a <code>fileInfo</code> object and we can’t assign a number to it. The compiler picks these things up before the program is ever run, so&nbsp; users don’t see run-time errors. <br />PowerShell isn’t compiled and its <u>Function declarations don’t include a return a type</u>: <code>Get-Item</code>, for example, deals with the file system, certificate stores, the registry etc. so it can return more than a dozen different types: there is no way to know in advance what type of item <code>Get-Item $y</code> will return. If the result is stored in a variable (with&nbsp; <code>$x = Get-item $y )</code>&nbsp; the type of the variable isn’t specified, but defined at runtime. <br />Trying to translate that declaration into PowerShell gives something like this.<br /><code>&nbsp; Function Get-Circumference{ <br />&nbsp; Param([single]$Radius) <br />&nbsp; $radius * 2 * [system.math]::PI<br />&nbsp; }</code> <br />Calling <br /><code>&nbsp; Get-Circumference "Hello"<br /></code>Produces an error but a closer inspection show it is not a type mismatch: it says<code> <br />Cannot process argument transformation on parameter 'radius'. Cannot convert value "hello" to type "System.Single".<br /></code>the <code>[Single] </code>says “always try to cast $f as a single”.&nbsp; Which means <br /><code>&nbsp; Get-Circumference "42"</code> <br />Will be cast from a string to a single and the function returns 263.89</p>
<p>So you might expect&nbsp; <br /><code>&nbsp; [System.IO.FileInfo]$f = Get-Circumference 42</code><br />To throw an error, but it doesn’t, PowerShell casts 263.893782901543 to an object representing a file with that name in \windows\system32. The file doesn’t exist and is read-only!&nbsp; So <strong>it can be better to resolve types in code. </strong></p>
<p>I’d go further than that. Some validation is redundant because the parameter will be passed to a cmdlet which is more flexible than the function writer thought, in other cases <strong>parameter validation is there to cover up <strong>a programmer’s laziness </strong>. </strong>When I see a web site which demands that I don’t enter spaces in my credit card number I think “Lazy. It’s easy to strip spaces and dashes”. Having “O’Neill” for a surname means that the work of slovenly developers who don’t check their SQL inputs or demand only letters gets drawn to my attention too. If the user is forced to use the equivalent of<br /><code>&nbsp; Stop-Process (get-process Calc)</code><br />they will think “Lazy. you&nbsp; couldn’t be bothered even to provide<strong> </strong>a <code>–name</code> parameter”.&nbsp; <code>Stop-process</code> does just that to cope with process objects, names and IDs (and notice it allows you to pass more than one ID)&nbsp; for example:<br /><code>&nbsp; stop-process [-id ] 4472,5200,5224<br />&nbsp; $p = get-process calc ; Stop-Process -InputObject $p&nbsp; <br />&nbsp; stop-process -name calc</code> </p>
<p>Other cmdlets are able to resolve types without using different parameters for example <br /><code>&nbsp; ren '.\100 Meter Event.txt' "100 Metre Event.txt"<br />&nbsp; $f = get-item '.\100 Metre Event.txt' ; ren $f '100 Meter Event.txt' <br /></code>In one case the first item is a string and the other is a file object: from a user’s point of view this is better than <code>stop-process</code> which in turn is much better than having to get an object representing the process you want to stop. In my talk I used <code>Set-VMMemory </code>from my <a href="http://pshyperv.codeplex.com">Hyper-V module on Codeplex</a>, which has:<br />&nbsp; <code>param(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [parameter(ValueFromPipeLine = $true)]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $VM,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Alias("MemoryInBytes")]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [long]$Memory = 0 ,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Server = "."<br />&nbsp; )</code><br />There isn’t a way for me to work out what a user means if they specify a memory size which isn’t a number (and can’t be cast to one). If the user specifies many Virtual Machines, catching something during parameter validation will produce one error instead of one per VM (so this would be the place to trap negative numbers too).<br />I have a -<em>server</em> parameter and it <strong>makes sense to assume</strong> the local machine – but I <strong>can’t make an assumption</strong> about which VM(s) the user might want to modify. The VM can come from the pipeline, and it might be an object which represents a VM, or a string with a VM name (possibly a wildcard) or an array of VM objects and/or Names. If the user says <br /><code>&nbsp; Set-VMMemory –memory 1GB –vm london* –server h1,h2</code><br />the function, not the user, translates that into the necessary objects. If this doesn’t match any VMs I don’t want things to break. (Though I might produce a warning). It takes 4 lines to support all of this <br />&nbsp;&nbsp; <code>if ($VM -is [String]) { $VM = Get-VM -Name $VM -Server $Server}<br />&nbsp; if ($VM.count -gt 1 )&nbsp; {[Void]$PSBoundParameters.Remove("VM") <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $VM | ForEach-object {Set-VMMemory -VM $_ @PSBoundParameters}}<br />&nbsp; if ($vm.__CLASS -eq 'Msvm_ComputerSystem') {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <em>do the main part of the code&nbsp; <br /></em>&nbsp; }</code>&nbsp; <br />Incidentally I use the __CLASS property because it works with remoting when other methods for checking a WMI type failed. </p>
<p><strong>Allow parts to be switched off </strong>In the talk I explained I have a script which applies new builds of software to a remote host. It does a backup and creates a roll back script. Sometimes I have to roll back, produce another build and then apply that. Since I have an up to date backup I don’t need to run the backup a second time so that part of the code runs unless I specify a –nobackup switch. </p>
<p><strong>Support –whatif&nbsp; or restore data. You choose. </strong>A function can use <code>$pscmdlet.shouldProcess </code>– which returns true if the function should proceed into a danger zone and false if it shouldn’t. It only takes one line&nbsp; line before declaring the parameters at the start of a function to enable this<br /><code>&nbsp; [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='High' )] <br /></code>There are 4 confirmation levels “None”, “Low”, “Medium,”, “High”, and for the Confirm impact value and the $Confirmation preference variable. If either is set to “None” no confirmation appears. If the impact level is higher or equal to the preference setting this line <br /><code>&nbsp; if ($pscmdlet.shouldProcess($file.name,”Delete file”) {Remove-item $file} <br /></code>Will delete the file or not depending on the users response to a prompt – in this case “Performing operation &#8220;Delete File&#8221; on Target &#8220;filename&#8221;. Confirmation can be forced on by specifying –<code>confirm. </code>Specifying <code>–whatif </code>will echo the message but return <em>false</em>. If no confirmation is needed, <code>&nbsp; <br />–verbose</code> will echo the message but return true. </p>
<p><strong>Prepare your code for other people, including you.&nbsp; </strong>I’m not the person I was a year ago. You’re not either, and we’ll be different people in 3 or 6 months. So even if you are not publishing your work are writing for someone else. You, in 3 months time. You under-pressure at 3 in the morning. And that you will curse the you of today if leave your code in a mess. </p>
<p>There are many ways to format your code: find a style of indenting that works for you, if it does, then the chances that anyone else will like it are about the same as the chance they will hate it.&nbsp; Some people like to play “PowerShell Golf” where fewest [key]strokes wins – this is fine for the command prompt. Expanding things to make them easier to read is generally good. That’s not an absolute ban on aliases – using Sort and Where instead of Sort-Object and Where-Object may help readability – the key is to break up very long lines, but without creating so many short lines that you are constantly scrolling up and down. </p>
<p>Everyone says “Put in brief comments”, but I’d refine that: explain WHY not WHAT, for example&nbsp; I only decided to use <code>Set-VMMemory </code>as an example in my talk at the last moment.&nbsp; It has a line<br /><code>&nbsp; if (-not ($memory % 2mb))&nbsp; {$memory /= 1mb}</p>
<p></code>
<p>I can’t have looked code in 8 months. Why would I do that ? Fortunately I’ve put in WHY comment – the WHAT is self explanatory<br /><code># The API takes the amount of memory in MB, in multiples of 2MB. <br /># Assume that anything less than 2097152 is in already MB (we aren't assigning 2TB to the VM). If user enters 1024MB or 0.5GB divide by 1MB&nbsp; </code>&gt;</p>
<p>Instead of putting comments next to each parameter saying what it does, move the comments into comment based help, take a couple of places where you have used / tested the command and put them into the comment based help as examples. Your future self will thank you for it. </p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/powershell/'>Powershell</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1776/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1776/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1776/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1776/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1776/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1776/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1776/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1776/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1776/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1776/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1776/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1776/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1776/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1776/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1776&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/10/24/maximize-the-reuse-of-your-powershell/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>

		<media:content url="http://jamesone111.files.wordpress.com/2011/10/image_thumb.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>
	</item>
		<item>
		<title>How to be Creative with QR Codes</title>
		<link>http://jamesone111.wordpress.com/2011/10/17/how-to-be-creative-with-qr-codes/</link>
		<comments>http://jamesone111.wordpress.com/2011/10/17/how-to-be-creative-with-qr-codes/#comments</comments>
		<pubDate>Mon, 17 Oct 2011 13:15:46 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/2011/10/17/how-to-be-creative-with-qr-codes/</guid>
		<description><![CDATA[I’ve been playing with QR codes recently, and have started to use them . HELLO if you’ve been at The Experts Conference in Frankfurt and scanned one of from one of my sessions the files form these are on My Skydrive&#160; I looked at a number of different code libraries which would build a QR [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1773&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I’ve been playing with QR codes recently, and have started to use them . HELLO if you’ve been at The Experts Conference in Frankfurt and scanned one of from one of my sessions the files form these are on <a title="https://skydrive.live.com/?cid=1efe2682bfbbd817&amp;sc=documents#cid=1EFE2682BFBBD817&amp;id=1EFE2682BFBBD817%21133&amp;sc=documents" href="https://skydrive.live.com/?cid=1efe2682bfbbd817&amp;sc=documents#cid=1EFE2682BFBBD817&amp;id=1EFE2682BFBBD817%21133&amp;sc=documents">My Skydrive</a>&nbsp;</p>
<p>I looked at a number of different code libraries which would build a QR code for me but the easiest way turned out to be to use a web service, provided by Google.&nbsp; And I wrapped this up in a little PowerShell </p>
<p><code><span style="color:#008080;">[System.Reflection.Assembly]</span><span style="color:#a9a9a9;">::</span><span style="color:#000000;">LoadWithPartialName</span><span style="color:#000000;">(</span><span style="color:#8b0000;">”System.Web"</span><span style="color:#000000;">)</span> <span style="color:#a9a9a9;">|</span> <span style="color:#0000ff;">Out-Null</span><br /><span style="color:#00008b;">Function</span> <span style="color:#8a2be2;">get-qrcode</span> <span style="color:#000000;">{</span><br /><span style="color:#00008b;">param</span> <span style="color:#000000;">(</span><span style="color:#a9a9a9;">[</span><span style="color:#00bfff;">parameter</span><span style="color:#000000;">(</span><span style="color:#000000;">ValueFromPipeLine</span><span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$true</span><span style="color:#a9a9a9;">,</span> <span style="color:#000000;">mandatory</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#ff4500;">$Text</span><span style="color:#a9a9a9;">,</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $path</span> <span style="color:#a9a9a9;">=</span> <span style="color:#000000;">(</span><span style="color:#0000ff;">join-path</span> <span style="color:#ff4500;">$pwd</span> <span style="color:#8b0000;">"QRCode.PNG"</span><span style="color:#000000;">)</span><br /><span style="color:#000000;">)</span><br /><span style="color:#00008b;">&nbsp; if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$WebClient</span> <span style="color:#a9a9a9;">-eq</span> <span style="color:#ff4500;">$null</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span><span style="color:#ff4500;">$Global:WebClient</span><span style="color:#a9a9a9;">=</span><span style="color:#0000ff;">new-object</span> <span style="color:#8a2be2;">System.Net.WebClient</span> <span style="color:#000000;">}</span><br /><span style="color:#ff4500;">&nbsp; $WebClient</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">DownloadFile</span><span style="color:#000000;">(</span><span style="color:#000000;">(</span><span style="color:#8b0000;">"http://chart.apis.google.com/chart?cht=qr&amp;chs=547x547&amp;chld=H|0&amp;chl="</span> <span style="color:#a9a9a9;">+</span><span style="color:#008080;">&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [System.Web.HttpUtility]</span><span style="color:#a9a9a9;">::</span><span style="color:#000000;">UrlEncode</span><span style="color:#000000;">(</span><span style="color:#ff4500;">$Text</span><span style="color:#000000;">)</span><span style="color:#000000;">)</span> <span style="color:#a9a9a9;">,</span> <span style="color:#ff4500;">$path</span><span style="color:#000000;">)</span> <br /><span style="color:#0000ff;">&nbsp;&nbsp; Start-Process</span> <span style="color:#ff4500;">$path</span><br /><span style="color:#000000;">}</span></code>
<p>So it takes two parameters, a block of text and a path where the file should be saved. The text must be specified, but there is a default for </p>
<p>To save having to the create lots of web client objects, I keep a web client object , then one line of powershell gets a PNG file from the Google Service and saves it to the path.&nbsp; Finally I launch the file in the default viewer.</p>
<p>The next step is to use some image tools to pretty up the QR code. I still use an ancient version of PaintShop pro and that does the job here nicely. </p>
<p><a href="http://jamesone111.files.wordpress.com/2011/10/qr-1.jpg"><img style="background-image:none;border-bottom:0;border-left:0;padding-left:0;padding-right:0;display:block;float:none;margin-left:auto;border-top:0;margin-right:auto;border-right:0;padding-top:0;" title="qr-1" border="0" alt="qr-1" src="http://jamesone111.files.wordpress.com/2011/10/qr-1_thumb.jpg?w=838&#038;h=278" width="838" height="278"></a></p>
<p>On the left is the original QR code, in the middle I have applied some gaussian blur to the image and on the right I have reduced this to two colours, 100% black and 100% white. This smoothes off the edges. Then I take the image back to 16 million colours and add some colour. </p>
<p>&nbsp;</p>
<p><a href="http://jamesone111.files.wordpress.com/2011/10/qr-2.jpg"><img style="background-image:none;border-bottom:0;border-left:0;padding-left:0;padding-right:0;display:block;float:none;margin-left:auto;border-top:0;margin-right:auto;border-right:0;padding-top:0;" title="qr-2" border="0" alt="qr-2" src="http://jamesone111.files.wordpress.com/2011/10/qr-2_thumb.jpg?w=558&#038;h=278" width="558" height="278"></a></p>
<p>One of the really nice things about QR codes is that they have error correction built in (and in my call to the web service I specify the maximum amount) this means we put something which isn’t part of the code into the picture. I’ve used the Frankfurt skyline from the slide template here, but this is scope for creativity. </p>
<p>Of course there is nothing which says the data in the code must be a URL. Here’s a message for anyone who has got a reader. The file name and the Ferrari might be a clue to what it says. </p>
<p align="center"><a href="http://jamesone111.files.wordpress.com/2011/10/qr-ferris.jpg"><img style="background-image:none;border-bottom:0;border-left:0;padding-left:0;padding-right:0;display:inline;border-top:0;border-right:0;padding-top:0;" title="QR-Ferris" border="0" alt="QR-Ferris" src="http://jamesone111.files.wordpress.com/2011/10/qr-ferris_thumb.jpg?w=500&#038;h=500" width="500" height="500"></a></p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/uncategorized/'>Uncategorized</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1773/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1773/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1773/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1773/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1773/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1773/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1773/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1773/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1773/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1773/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1773/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1773/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1773/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1773/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1773&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/10/17/how-to-be-creative-with-qr-codes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>

		<media:content url="http://jamesone111.files.wordpress.com/2011/10/qr-1_thumb.jpg" medium="image">
			<media:title type="html">qr-1</media:title>
		</media:content>

		<media:content url="http://jamesone111.files.wordpress.com/2011/10/qr-2_thumb.jpg" medium="image">
			<media:title type="html">qr-2</media:title>
		</media:content>

		<media:content url="http://jamesone111.files.wordpress.com/2011/10/qr-ferris_thumb.jpg" medium="image">
			<media:title type="html">QR-Ferris</media:title>
		</media:content>
	</item>
		<item>
		<title>Adding $Clipboard automatic variable support to PowerShell</title>
		<link>http://jamesone111.wordpress.com/2011/09/11/adding-clipboard-automatic-variable-support-to-powershell/</link>
		<comments>http://jamesone111.wordpress.com/2011/09/11/adding-clipboard-automatic-variable-support-to-powershell/#comments</comments>
		<pubDate>Sun, 11 Sep 2011 17:08:42 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Powershell]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/2011/09/11/adding-clipboard-automatic-variable-support-to-powershell/</guid>
		<description><![CDATA[Some of the bits and pieces I have been working on recently have needed PowerShell to take input from the windows clipboard, and as with so many things in PowerShell there is more than one way this can be done. If it is something short paste into a command line –wrapping in quotes or @” [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1765&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Some of the bits and pieces I have been working on recently have needed PowerShell to take input from the windows clipboard, and as with so many things in PowerShell there is more than one way this can be done. </p>
<ul>
<li>If it is something short paste into a command line –wrapping in quotes or @” “@ as required
<li>Paste into a new edit window in the PowerShell ISE and wrap it with $variableName = “” (or @” “@ as required) , then run the contents of the Window
<li>Use&nbsp; [windows.clipboard]::GetText() in a command line
<li>Create a Get-Clipboard Function which wraps&nbsp; [windows.clipboard]::GetText()
<li>Create a $Clipboard “automatic variable”
<li>Use the <a href="http://huddledmasses.org/clipexe-and-the-missing-pasteexe/">Paste.Exe which Joel has on his site.</a></li>
</ul>
<p>Note (a) that if you want to use&nbsp; [windows.clipboard]::GetText() in the “Shell” version of PowerShell you need to start PowerShell.exe with the –STA switch and run the command&nbsp;&nbsp; Add-Type -AssemblyName (&#8220;Presentationcore&#8221;) – I’m actually only interested in doing this in the ISE. <br />and (b) If you want to send PowerShell’s output to the clipboard the command line Clip.exe has been Windows for several versions. It’s getting text from the clipboard which needs more work. </p>
<p>There’s very little to choose between having Get-Clipboard and $clipboard but having just read <a href="http://robertrobelo.wordpress.com/2011/06/24/tied-variables-a-simpler-way/">Robert’s piece on <strong>Tied Variables</strong></a> I thought I would go down that path. </p>
<p>Robert explained that you can set a <strong>breakpoint </strong>on a PowerShell variable to run a <strong>scriptblock</strong> when the<strong> variable is read, </strong>so he got to thinking “I can run something which <strong>changes the value of variable, </strong>when it is read. </p>
<p>In my profile I have </p>
<p><code><span style="color:#ff4500;"><font color="#00008b"></font>$Global:MyBreakPoint</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$Global:Clipboard</span> <span style="color:#a9a9a9;">=</span> <span style="color:#0000ff;">Set-PSBreakpoint</span> <span style="color:#000080;">-Variable</span> <span style="color:#8a2be2;">Clipboard</span> <span style="color:#000080;">-Mode</span> <span style="color:#8a2be2;">Read</span> <span style="color:#000080;">-Action</span> <span style="color:#000000;">{</span><br /><span style="color:#0000ff;">Set-Variable</span> <span style="color:#8a2be2;">clipboard</span> <span style="color:#000000;">(</span><span style="color:#008080;">[Windows.clipboard]</span><span style="color:#a9a9a9;">::</span><span style="color:#000000;">GetText</span><span style="color:#000000;">(</span><span style="color:#000000;">)</span><span style="color:#000000;">)</span> <span style="color:#000080;">-Option</span> <span style="color:#8a2be2;">ReadOnly</span><span style="color:#a9a9a9;">,</span> <span style="color:#8a2be2;">AllScope</span> <span style="color:#000080;">-Scope</span> <span style="color:#8a2be2;">Global</span> <span style="color:#000080;">-Force</span><span style="color:#000000;">}</span></code>
<p>So <code>$clipboard</code> is set to the breakpoint which is created by monitoring read action on itself. At each subsequent read the script-block is called and uses <code>set-variable</code> to make <code>$clipboard</code> a ReadOnly variable holding the value of the clipboard at that moment.</p>
<p>In the I modified my <code>Get-SQL</code> command to take advantage of this. I added a <code>–Paste</code> switch (I chose –paste over –clipboard simply because I already had –connection so –c would be ambiguous –paste allows me to run <code>sql –p</code> , taking advantage of SQL being an automatic alias for Get-SQL) then </p>
<p><code><span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$Paste</span> <span style="color:#a9a9a9;">-and</span> <span style="color:#000000;">(</span><span style="color:#0000ff;">test-path</span> <span style="color:#8b0000;">'Variable:\Clipboard'</span><span style="color:#000000;">)</span><span style="color:#000000;">)</span> <br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp; {</span><span style="color:#ff4500;">$sql</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$Clipboard</span> <span style="color:#a9a9a9;">-replace</span> <span style="color:#8b0000;">".*(?=select|update|delete)"</span><span style="color:#a9a9a9;">,</span><span style="color:#8b0000;">""</span> <span style="color:#a9a9a9;">-replace</span> <span style="color:#8b0000;">"[\n|\r]+"</span><span style="color:#a9a9a9;">,</span><span style="color:#8b0000;">""</span> <span style="color:#000000;">}</span><br /></code>
<p>This trims out anything before “Select”, “update” or “Delete” –as I am usually copying a statement from a log with a time stamp at the start, and it also replaces any carriage return/line feed characters. </p>
<h2>WHAT ? A bug in the PowerShell ISE</h2>
<p><a href="http://jamesone111.files.wordpress.com/2011/09/image.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;float:left;padding-top:0;border-width:0;" title="image" border="0" alt="image" align="left" src="http://jamesone111.files.wordpress.com/2011/09/image_thumb.png?w=244&#038;h=90" width="244" height="90"></a>This was all working brilliantly until I went to use a function which uses the PowerShellISE object model to manipulate text in an edit window it fails – the error implies that PowerShell’s object model thinks a debugger is running if a break point exists, even though trying to edit the script files interactively is not a problem . </p>
<p>To get around this I set TWO variables to point to the break point, one was $clipboard, which will be overwritten as soon as it is used, and the other is $myBreakPoint. In my edit function I now start with </p>
<p><code><span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$MyBreakPoint</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span><span style="color:#0000ff;">Remove-PSBreakpoint</span> <span style="color:#ff4500;">$MyBreakPoint</span> <span style="color:#000000;">}</span> </code></p>
<p>Removing the breakpoint doesn’t remove the variable $myBreakpoint so on the way out of the function I use it to decide if I need to reinstate it. </p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/powershell/'>Powershell</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1765/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1765/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1765/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1765/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1765/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1765/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1765/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1765/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1765/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1765/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1765/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1765/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1765/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1765/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1765&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/09/11/adding-clipboard-automatic-variable-support-to-powershell/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>

		<media:content url="http://jamesone111.files.wordpress.com/2011/09/image_thumb.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>
	</item>
		<item>
		<title>Round-tripping files for editing</title>
		<link>http://jamesone111.wordpress.com/2011/09/02/round-tripping-files-for-editing/</link>
		<comments>http://jamesone111.wordpress.com/2011/09/02/round-tripping-files-for-editing/#comments</comments>
		<pubDate>Fri, 02 Sep 2011 21:20:14 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Powershell]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/2011/09/02/round-tripping-files-for-editing/</guid>
		<description><![CDATA[Watching a quiz the other day the host said of a book “I plan to start [it] the moment my Doctor tells me I have 2000 years to live”. It’s was a great spin on “life’s too short to…” I my case life is too short to re-learn how to use vi.&#160; I learned how [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1762&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Watching a quiz the other day the host said of a book “I plan to start [it] the moment my Doctor tells me I have 2000 years to live”. It’s was a great spin on “life’s too short to…” I my case<strong> life is too short to re-learn how to use vi</strong>.&nbsp; I learned how to use it on Wyse terminals at university in the mid 1980s, and I didn’t rate it then. If <a href="http://en.wikipedia.org/wiki/Vi">wikipedia</a> has its facts right vi was dates back to 1976; Steve Jobs and Steve Wozniak had yet to launch the Apple II had IBM hadn’t even thought of making a PC, and the supercomputers in the best equipment research facilities had less power than today’s SmartPhones. In computer terms dinosaurs were still roaming the earth, and must make vi the <em>coelacanth </em>of software, ugly as hell and somehow immune to the forces which should have rendered it extinct. </p>
<p>I’m working with a Linux server which I can only access over an SSH session. Since configuring the server means editing text files some thought has gone into how to avoid vi.&nbsp; We’ve standardized on <a href="http://sshexplorer.com/">SSH explorer</a> in the office – it can round-trip files to the PC for editing. I’ve <a href="https://jamesone111.wordpress.com/2011/08/23/enhancing-the-netcmdlets/">recently been using the netcmdlets</a><strong></strong> to move files around and I’ve also been looking at <a href="https://jamesone111.wordpress.com/2011/07/27/a-tail-command-in-powershell/">trapping file-changed events</a><strong></strong> I found myself asking “How difficult would it be to transfer a file to a temporary folder, load it into the editor of my choice and push it back to where it came from when it was saved?”. The answer turns out “about this difficult …”</p>
<p><code><span style="color:#00008b;">Function</span> <span style="color:#8a2be2;">Edit-RemoteItem</span> <span style="color:#000000;">{</span><br /><span style="color:#00008b;">param</span> <span style="color:#000000;">(</span><span style="color:#a9a9a9;">[</span><span style="color:#add8e6;">Parameter</span><span style="color:#000000;">(</span><span style="color:#000000;">ValueFromPipeLine</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#a9a9a9;">,</span> <span style="color:#000000;">ValueFromPipelineByPropertyName</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#a9a9a9;">,</span> <span style="color:#000000;">mandatory</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#008080;">[String]</span><span style="color:#ff4500;">$path</span><span style="color:#a9a9a9;">,</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Connection</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$Global:ssh</span><br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $localpath</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#a9a9a9;">=</span>&nbsp; <span style="color:#000000;">( </span><span style="color:#0000ff;">join-path</span> <span style="color:#ff4500;">$env:temp</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$path</span> <span style="color:#a9a9a9;">-split</span> <span style="color:#8b0000;">"/"</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">[</span><span style="color:#800080;">-1</span><span style="color:#a9a9a9;">]</span><span style="color:#000000;">)</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $MessageDataHT</span> <span style="color:#a9a9a9;"><a href="mailto:=@{&nbsp;&nbsp;&nbsp; Server=$connection.Server">= </span><span style="color:#000000;">@{&nbsp;&nbsp; </span><span style="color:#000000;">Server</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$connection</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Server</a></span><span style="color:#000000;">;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;<span style="color:#000000;">RemoteFile</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$path</span><span style="color:#000000;">;</span>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000000;">Credential</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$connection</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Credential</span><span style="color:#000000;">;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000000;">LocalFile</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$localpath</span><span style="color:#000000;">;</span>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000000;">force</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#000000;">;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;<span style="color:#000000;">Overwrite</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#000000;">}</span> <br /><span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Get-SFTP</span> <span style="color:#ff4500;">@MessageDataHT</span> <span style="color:#a9a9a9;">|</span> <span style="color:#0000ff;">out-null</span> <br /><span style="color:#00008b;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if</span> <span style="color:#000000;">( </span><span style="color:#ff4500;">$Host</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Name</span> <span style="color:#a9a9a9;">-match</span> <span style="color:#8b0000;">"\sISE\s" </span><span style="color:#000000;">)</span><br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { </span><span style="color:#ff4500;">$null</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$psISE</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">CurrentPowerShellTab</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Files</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Add</span><span style="color:#000000;">(</span><span style="color:#ff4500;">$localpath</span><span style="color:#000000;">)</span> <span style="color:#000000;">}</span><br /><span style="color:#00008b;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else</span> <span style="color:#000000;">{</span> <span style="color:#0000ff;">notepad.exe</span> <span style="color:#ff4500;">$localpath</span> <span style="color:#000000;">}</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Global:watcher</span> <span style="color:#a9a9a9;">=</span> <span style="color:#0000ff;">Register-FileSystemWatcher</span> <span style="color:#000080;">-MessageData</span> <span style="color:#ff4500;">$MessageDataHT</span> <span style="color:#000080;">-Path</span> <span style="color:#ff4500;">$localpath</span> `<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000080;">-On</span> <span style="color:#8b0000;">"Changed" </span><span style="color:#000080;">-Process</span> <span style="color:#000000;">{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#ff4500;">$event</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">sender</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">enableRaisingEvents</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$false</span>&nbsp;<br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $oldpp</span> <span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$ProgressPreference</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ProgressPreference</span><span style="color:#a9a9a9;">=</span><span style="color:#8b0000;">"silentlycontinue"</span><br /><span style="color:#00008b;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if</span> <span style="color:#000000;">(</span><span style="color:#000000;">(</span><span style="color:#0000ff;">Send-SFTP</span> –<span style="color:#000080;">server</span>&nbsp; </code><code><span style="color:#ff4500;">$event</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">MessageData</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">server</span> `<br /><span style="color:#000080;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -LocalFile</span>&nbsp; <span style="color:#ff4500;">$event</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">MessageData</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">LocalFile</span> `<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000080;">-RemoteFile</span> <span style="color:#ff4500;">$event</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">MessageData</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">RemoteFile</span> `<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000080;">-Credential</span> <span style="color:#ff4500;">$event</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">MessageData</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Credential`</span>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000080;">-Overwrite</span> <span style="color:#000080;">-Force</span> <span style="color:#000000;">)</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">size</span><span style="color:#000000;">) </span><span style="color:#000000;">{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#0000ff;">Write-host</span> <span style="color:#8b0000;">"Updated $($event.MessageData.RemoteFile on $($event.MessageData.server)"<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#000000;">}</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ProgressPreference</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$oldpp</span>&nbsp;<br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $event</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">sender</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">enableRaisingEvents</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$True<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#000000;">}</span> <br /><span style="color:#000000;">}</span><br /></code>To run through the function quickly; it takes a remote path and a netcmdlets SSH connection object.&nbsp; It builds a local path and a hash table with parameters in and calls Get-SFTP by <em>splatting</em> – turning each key/value pair in the hash table into a parameter/value pair. </p>
<p>If it is running in the PowerShell ISE it loads the transferred file into PowerShell’s editor, otherwise it loads it into notepad. </p>
<p>Then it sets up a FileSystem watcher using the same code I talked about <a href="https://jamesone111.wordpress.com/2011/07/27/a-tail-command-in-powershell/">here</a>&nbsp; The watcher is passed the same hash table of parameters – unfortunately you can’t use splatting in a process block and there is no option to hide the progress bar, so I temporarily change the $Progress preference and change it back when I’ve finished. I also make sure that while the upload is happening no new events are raised. In between I call send-Sftp inserting parameters from the hash table: simples. </p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/powershell/'>Powershell</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1762/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1762/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1762/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1762/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1762/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1762/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1762/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1762/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1762/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1762/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1762/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1762/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1762/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1762/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1762&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/09/02/round-tripping-files-for-editing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>
	</item>
		<item>
		<title>Improving my score at PowerShell Golf</title>
		<link>http://jamesone111.wordpress.com/2011/08/24/improving-my-score-at-powershell-golf/</link>
		<comments>http://jamesone111.wordpress.com/2011/08/24/improving-my-score-at-powershell-golf/#comments</comments>
		<pubDate>Wed, 24 Aug 2011 09:58:09 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Powershell]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/2011/08/24/improving-my-score-at-powershell-golf/</guid>
		<description><![CDATA[There is mindset found in among scripting and programming people known as &#8220;Golf&#8221;. The objective is to get to the end using as few [key]strokes as possible. It&#8217;s not something I like to see in scripts and functions, but most of us don&#8217;t like to type any more than we have to at the command [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1761&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>There is mindset found in among scripting and programming people known as &#8220;Golf&#8221;. The objective is to get to the end using as few [key]strokes as possible. It&#8217;s not something I like to see in scripts and functions, but most of us don&#8217;t like to type any more than we have to at the command line. Tab expansion in PowerShell is a great feature for cutting down keystrokes (not beyond improvement, but truly great).
<p>I&#8217;ve mentioned a couple of times recently that PowerShell’s parser gives <code>GET-</code> commands a sort of “automatic alias”: if you type “<code>Service</code>” where a command is expected, tab expansion won’t work but if you carry on and run the command, then&nbsp; before it gives up and reports “<code>The term 'service' is not recognized as the name of a cmdlet, function, script file, or operable program.</code>” PowerShell looks for “Get-Service” finds it and calls that instead.&nbsp; This works for user defined functions as well , so <a href="https://jamesone111.wordpress.com/2011/08/22/easy-formating-for-powershell-with/">the Get-SQL command I wrote</a> to send SQL commands via ODBC can be shortened to “SQL”, which is very fine and good and only has two things wrong with it.
<ol>
<li>Commands need to wrapped in quotes. It doesn&#8217;t matter if they are single or double quotes, but if you are pasting in something which was written for MySQL you need to have your wits about you because like PowerShell it allows you to use single or double quotes in the command .
<li>It&#8217;s still more keystrokes than using the MySQL Monitor in an SSH session. </li>
</ol>
<p>What I wanted to do was use a symbol to mean “Send this to SQL&#8221;.”PowerShell already uses most of the symbols on the keyboard, although its parser is flexible enough to allow some to be used as aliases &#8211; for example when it sees &#8220;<code>40 % 13</code>&#8221; the <code>%</code> sign is interpreted as the &#8220;modulo&#8221; operator but when it sees &#8220;<code>dir | % {…</code>&#8221; <code>%</code> is an alias for &#8220;<code>ForEach-Object</code>&#8221; . Possible though it is, making the $ or &gt; signs into aliases feels like the first dancing step down the path to madness, so for SQL I used ¬ (I&#8217;ve used the same technique for the <a href="https://jamesone111.wordpress.com/2011/08/23/enhancing-the-netcmdlets/">Invoke-RemoteCommand wrapper I wrote for the netCmdlets</a> Invoke-SSH command for which I use ~ )
<p>I <u>want</u> to be able to type<br /><code>¬ select * from mytable where name="james"</code> <br />and have my command go into the default ODBC connection (or the default SSH connection or whatever) .<br />But <strong>it won&#8217;t work</strong> if I simply use <code>Set-Alias -Name "¬" -Value "Get-SQL"</code> , because &#8220;Select&#8221;,&#8221;*&#8221;,&#8221;from&#8221;, &#8220;mytable&#8221; and so on each get <strong>treated as distinct parameters and the quote marks will be lost</strong> around <em>james</em>. PowerShell has a &#8220;ValueFromRemainingArguments&#8221; option for a parameter but that won&#8217;t deal with the quotes issue (and there will be an problems deciding what belongs to other parameters like the ODBC connection string ).
<p>My solution was to alias ¬ to an <strong>intermediate function</strong> named Hide-GetSql which contains 1 line <code><br /><span style="color:#00008b;">Function</span> <span style="color:#8a2be2;">Hide-GetSQL</span> <span style="color:#000000;">{</span><br /><span style="color:#0000ff;">&nbsp; Get-Sql</span> <span style="color:#000080;">-sql</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$MyInvocation</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">line</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">substring</span><span style="color:#000000;">(</span><span style="color:#ff4500;">$MyInvocation</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">OffsetInLine</span><span style="color:#000000;">)</span><span style="color:#000000;">)</span> <br /><span style="color:#000000;">}</span> <br /><span style="color:#0000ff;">Set-Alias</span> <span style="color:#000080;">-Name</span> <span style="color:#8a2be2;">¬</span> <span style="color:#000080;">-Value</span> <span style="color:#8a2be2;">Hide-GetSQL</span> <br /></code>
<p>Normally I hate seeing references to $Args or $MyInvocation.line but here I have to make an exception, this gets the line which was used as a single string and truncates it after the function / alias name.&nbsp; PowerShell&#8217;s parser will try to split this line into sections if it contains semi colons – the function still works, but any attempt to process a second command will almost certainly cause a spurious error. For my use it hasn’t been a problem – your mileage may vary. </p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/powershell/'>Powershell</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1761/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1761/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1761/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1761/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1761/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1761/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1761/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1761/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1761/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1761/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1761/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1761/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1761/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1761/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1761&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/08/24/improving-my-score-at-powershell-golf/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>
	</item>
		<item>
		<title>Enhancing the NetCmdlets</title>
		<link>http://jamesone111.wordpress.com/2011/08/23/enhancing-the-netcmdlets/</link>
		<comments>http://jamesone111.wordpress.com/2011/08/23/enhancing-the-netcmdlets/#comments</comments>
		<pubDate>Tue, 23 Aug 2011 13:11:21 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Powershell]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/2011/08/23/enhancing-the-netcmdlets/</guid>
		<description><![CDATA[At PowerShell Deep dive conference in April /n software gave away USB keys with a full set of “PowerShell inside” software including their NetCmdlets. It turns out that this is 30 day evaluation software, and initially this put me off using them; Joel wrote about an alternative saying “It’s also possible to do this using [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1760&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>At PowerShell Deep dive conference in April /n software gave away USB keys with a full set of “PowerShell inside” software including their <a href="http://www.nsoftware.com/powershell/">NetCmdlets.</a> It turns out that this is 30 day evaluation software, and initially this put me off using them; <a href="http://huddledmasses.org/scriptable-ssh-from-powershell/">Joel wrote about an alternative</a> saying <em>“It’s also possible to do this using the </em><a href="http://www.nsoftware.com/powershell/"><em>NetCmdlets from /n</em></a><em> and I’m constantly surprised at how unwilling people are to pay for them.”</em>&nbsp; Part of the problem is you get nearly 100 cmdlets, and if you want only half a dozen if feels like most of the cost is wasted. After checking a free library and finding it flakey I dug out the USB key, figuring if they worked, or even <em>mostly</em> worked they’d be worth the cost.</p>
<p>I only need to do a couple of things – use SSH to send commands to the Linux server which hosts my application using (for which there are 3 commands: <code>Connect-SSH</code>, <code>Disconnect-SSH</code> and <code>Invoke-SSH</code>) and move files both ways with sftp (which has <code>Connect-SFTP, Disconnect-SFTP, Get-SFTP, Remove-SFTP, Rename-SFTP</code> and <code>Send-SFTP</code>) .&nbsp; I wanted to be able to invoke the commands against my server without re-making connections each time , and that meant some simple “wrapper” commands to get things how I wanted them. </p>
<blockquote><p>
<table border="0" cellspacing="0" cellpadding="2" width="100%">
<tbody>
<tr>
<td valign="top" width="200"><code>Connect-Remote</code></td>
<td valign="top">Sets up a Remote Session (saves the session object as a global variable)<br />All the following functions can be passed a remote session but use the global variable as a default </td>
</tr>
<tr>
<td valign="top" width="200"><code>Get-RemoteItem</code></td>
<td valign="top">Get properties one or more remote items (Like Get-Item / Get-ChildItem) – <strong>alias</strong> rDir </td>
</tr>
<tr>
<td valign="top" width="200"><code>Copy-RemoteItem</code></td>
<td valign="top">Copies a remote item to the local computer (like Copy-Item ) –<strong>alias</strong> rCopy</td>
</tr>
<tr>
<td valign="top" width="200"><code>Copy-LocalItem</code></td>
<td valign="top">Copies a local item to the remote computer</td>
</tr>
<tr>
<td valign="top" width="200"><code>Remove-RemoteItem</code></td>
<td valign="top">Deletes an item on the remote computer&nbsp; (like Remove-Item)</td>
</tr>
<tr>
<td valign="top" width="200"><code>Invoke-RemoteCommand</code></td>
<td valign="top">Runs a command on the remote computer. (Like Invoke-Command)</td>
</tr>
</tbody>
</table>
</blockquote>
<p>The two connect- netcmdlets return different types of object which contain the server, credential and various other connection parameters. I can set them up like this </p>
<p><code><span style="color:#ff4500;">$credential</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$Host</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">ui</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">PromptForCredential</span><span style="color:#000000;">(</span><span style="color:#8b0000;">"Login"</span><span style="color:#a9a9a9;">,<br /></span><span style="color:#8b0000;">&nbsp;&nbsp; "Enter Your Details for $server"</span><span style="color:#a9a9a9;">,</span><span style="color:#8b0000;">"$env:userName"</span><span style="color:#a9a9a9;">,</span><span style="color:#8b0000;">""</span><span style="color:#000000;">)</span> <br /><span style="color:#ff4500;">$Global:ssh</span> <span style="color:#a9a9a9;">=</span> <span style="color:#0000ff;">Connect-SSH</span> <span style="color:#000080;">-Server</span> <span style="color:#ff4500;">$server</span> <span style="color:#000080;">-Credential</span> <span style="color:#ff4500;">$credential</span> –<span style="color:#000080;">Force</span> <br /></code>
<p>I found downloading causes the <u>sftp</u>Connection object to “stick” to the path of downloaded file. Get-, Remove-, Rename- and Send- all allow the server and credential to be passed, so I can pass the <u>SSH</u>Connection object into my SFTP wrappers and use its server and credential properties – even though it is the “wrong” connection type – being for SSH command-lines rather than SFTP file access. I wrote a Connect-Remote function which also stores the connections so I can switch between them more easily. It looks like this: </p>
<p><code><span style="color:#ff4500;">$Global:AllSSHConnections</span> <span style="color:#a9a9a9;">=</span> <span style="color:#000000;">@{</span><span style="color:#000000;">}</span> <br /><span style="color:#00008b;">Function</span> <span style="color:#8a2be2;">Connect-Remote</span> <span style="color:#000000;">{</span>&nbsp;<br /><span style="color:#00008b;"><span style="color:#00008b;">Param</span> <span style="color:#000000;">(</span><span style="color:#008080;">[String]</span><span style="color:#ff4500;">$server</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$global:server</span><span style="color:#a9a9a9;">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#008080;">[String]</span><span style="color:#ff4500;">$UserName</span> <span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$env:userName</span> <span style="color:#a9a9a9;">,</span>&nbsp;<br /><span style="color:#008080;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#008080;">[Switch]</span><span style="color:#ff4500;">$force<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></code><code><span style="color:#00008b;"><span style="color:#000000;">)<br /></span>&nbsp;<span style="color:#00008b;"></span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#00008b;">if</span>&nbsp;&nbsp; <span style="color:#000000;">(</span><span style="color:#ff4500;">$Global:AllSSHConnections</span><span style="color:#a9a9a9;">[</span><span style="color:#ff4500;">$server</span><span style="color:#a9a9a9;">]</span> <span style="color:#a9a9a9;">-and</span> <span style="color:#a9a9a9;">-not</span> <span style="color:#ff4500;">$force</span><span style="color:#000000;">)</span> <span style="color:#000000;">{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></code><code><span style="color:#ff4500;">$Global:ssh</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$Global:AllSSHConnections</span><span style="color:#a9a9a9;">[</span><span style="color:#ff4500;">$server</span><span style="color:#a9a9a9;">]</span><span style="color:#000000;">}</span>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#00008b;">else</span> <span style="color:#000000;">{</span> <span style="color:#ff4500;">$credential</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$Host</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">ui</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">PromptForCredential</span><span style="color:#000000;">(</span><span style="color:#8b0000;">"Login"</span><span style="color:#a9a9a9;">,</span><span style="color:#8b0000;">"Enter Your Details for $server"</span><span style="color:#a9a9a9;">,</span><span style="color:#ff4500;">$username</span><span style="color:#a9a9a9;">,</span><span style="color:#8b0000;">""</span><span style="color:#000000;">)</span><br /><span style="color:#006400;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Connect-ssh takes errorAction parameter but it doesn't work. So use try-catch&nbsp; </span><br /><span style="color:#00008b;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try</span> <span style="color:#000000;">{</span><span style="color:#ff4500;">$Global:ssh</span> <span style="color:#a9a9a9;">=</span> <span style="color:#0000ff;">Connect-SSH</span> <span style="color:#000080;">-Server</span> <span style="color:#ff4500;">$server</span> <span style="color:#000080;">-Credential</span> <span style="color:#ff4500;">$credential</span> <span style="color:#000080;">-Force</span> <span style="color:#000080;">-ErrorVariable</span> <span style="color:#8a2be2;">SSHErr</span> <span style="color:#000000;">}</span><br /><span style="color:#00008b;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch</span> <span style="color:#000000;">{</span><span style="color:#00008b;">continue</span><span style="color:#000000;">}</span> <br /><span style="color:#00008b;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$?</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span><span style="color:#ff4500;">$remotehost</span> <span style="color:#a9a9a9;">=</span> <span style="color:#000000;">(</span><span style="color:#0000ff;">invoke-RemoteCommand</span> <span style="color:#000080;">-Connection</span> <span style="color:#ff4500;">$ssh</span> <span style="color:#000080;">-CmdLine</span> <span style="color:#8b0000;">"hostname"</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">[</span><span style="color:#800080;">0</span><span style="color:#a9a9a9;">]</span> <span style="color:#a9a9a9;">-replace</span> <span style="color:#8b0000;">"\W*$"</span><span style="color:#a9a9a9;">,</span><span style="color:#8b0000;">""</span><br /><span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Add-Member</span> <span style="color:#000080;">-InputObject</span> <span style="color:#ff4500;">$ssh</span> <span style="color:#000080;">-MemberType</span> <span style="color:#8b0000;">"NoteProperty"</span> <span style="color:#000080;">-Name</span> <span style="color:#8b0000;">"HostName"</span> <span style="color:#000080;">-Value</span> <span style="color:#ff4500;">$remoteHost</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Global:AllSSHConnections</span><span style="color:#a9a9a9;">[</span><span style="color:#ff4500;">$server</span><span style="color:#a9a9a9;">]</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$ssh</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ssh</span> <span style="color:#a9a9a9;">|</span> <span style="color:#0000ff;">out-default</span>&nbsp;<br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />}</span></span></code></p>
<p>Storing the connection simplifies using the other cmdlets. I have a little more error checking in the real version of the script so I can tell the user if there was simply a password error or something more fundamental at fault. </p>
<p>The first task I wanted to perform was to get a file listing via sftp. I have a couple of easily-solved gripes with the netcmdlets: I’ve already mentioned the sticking sftp connection, the other is that the EntryInfo object which is returned when getting a file listing doesn’t contain the fully qualified path, just the file name – so I sort the entries into order, and add properties for the directory and fully qualified path and used <a href="http://jamesone111.wordpress.com/2011/08/22/easy-formating-for-powershell-with/">New-TableFormat</a>&nbsp; to give me the start of a formatting XML file to display the files nicely . The function also takes the path, and a connection object – which defaults to the connection I set up before.</p>
<p><code><span style="color:#00008b;">Function</span> <span style="color:#8a2be2;">Get-RemoteItem</span> <span style="color:#000000;">{</span><br /><span style="color:#00008b;">&nbsp;&nbsp;&nbsp; param</span><span style="color:#000000;">( </span><span style="color:#a9a9a9;">[</span><span style="color:#add8e6;">Parameter</span><span style="color:#000000;">(</span><span style="color:#000000;">ValueFromPipeLine</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#008080;">[String]</span><span style="color:#ff4500;">$path</span><span style="color:#a9a9a9;">=</span> <span style="color:#8b0000;">"/*"</span><span style="color:#a9a9a9;">,</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Connection&nbsp; </span><span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$Global:ssh</span>&nbsp;<br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )</span><br /><span style="color:#00008b;">process</span> <span style="color:#000000;">{</span><br /><span style="color:#00008b;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$Connection</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">server</span> <span style="color:#a9a9a9;">-and</span> <span style="color:#ff4500;">$Connection</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Credential</span> <span style="color:#000000;">)</span> <span style="color:#000000;">{<font color="#006400"><br /></font></span><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Directory</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$path</span> <span style="color:#a9a9a9;">-replace</span> <span style="color:#8b0000;">"/[^/]*$"</span><span style="color:#a9a9a9;">,</span><span style="color:#8b0000;">""</span>&nbsp;<br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#0000ff;">Get-sftp</span> <span style="color:#000080;">-List</span> <span style="color:#ff4500;">$path</span> <span style="color:#000080;">-Credential</span> <span style="color:#ff4500;">$Connection</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Credential`<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#000080;">-Server</span> <span style="color:#ff4500;">$Connection</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Server</span> <span style="color:#000080;">-force</span> <span style="color:#a9a9a9;">|</span>&nbsp;<br /><span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Sort-Object</span> <span style="color:#000080;">-property</span> <span style="color:#000000;">@{</span><span style="color:#000000;">e</span><span style="color:#a9a9a9;">=</span><span style="color:#000000;">{</span><span style="color:#a9a9a9;">-not</span> <span style="color:#ff4500;">$_</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">isdir</span><span style="color:#000000;">}</span><span style="color:#000000;">}</span><span style="color:#a9a9a9;">,</span> <span style="color:#8a2be2;">filename</span> <span style="color:#a9a9a9;">|</span>&nbsp;<br /><span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Add-Member</span> <span style="color:#000080;">-MemberType</span> <span style="color:#8a2be2;">NoteProperty</span>&nbsp;&nbsp; <span style="color:#000080;">-Name</span> <span style="color:#8b0000;">"directory"</span> <span style="color:#000080;">-Value</span> <span style="color:#ff4500;">$directory</span> <span style="color:#000080;">-PassThru</span> <span style="color:#a9a9a9;">|</span>&nbsp;<br /><span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Add-Member</span> –<span style="color:#000080;">MemberType</span> <span style="color:#8a2be2;">ScriptProperty</span> <span style="color:#000080;">-Name</span> <span style="color:#8b0000;">"Path"</span> `<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000080;">-Value</span> <span style="color:#000000;">{</span><span style="color:#ff4500;">$this</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">directory</span> <span style="color:#a9a9a9;">+</span> <span style="color:#8b0000;">"/"</span> <span style="color:#a9a9a9;">+</span> <span style="color:#ff4500;">$this</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Filename</span><span style="color:#000000;">}</span> –<span style="color:#000080;">PassThru</span><br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="color:#00008b;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else</span> <span style="color:#000000;">{</span><span style="color:#0000ff;">write-warning</span> <span style="color:#8b0000;">"We don't appear to have a valid connection."</span><span style="color:#000000;">}</span> <br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="color:#000000;">}</span><br /></code>
<p>The next things to add were copy-RemoteItem and Copy-LocalItem – which just have to call Get-SFTP and Send-SFTP with some pre-set parameters. </p>
<p><code><span style="color:#00008b;">Function</span> <span style="color:#8a2be2;">Copy-RemoteItem</span> <span style="color:#000000;">{</span><br /><span style="color:#a9a9a9;">[</span><span style="color:#add8e6;">CmdletBinding</span><span style="color:#000000;">(</span><span style="color:#000000;">SupportsShouldProcess</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]</span><br /><span style="color:#00008b;">param</span> <span style="color:#000000;">(</span><span style="color:#a9a9a9;">[</span><span style="color:#add8e6;">Parameter</span><span style="color:#000000;">(</span><span style="color:#000000;">ValueFromPipeLine</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#a9a9a9;">,</span> <span style="color:#000000;">ValueFromPipelineByPropertyName</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#a9a9a9;">,</span> <span style="color:#000000;">mandatory</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#008080;">[String]</span><span style="color:#ff4500;">$path</span><span style="color:#a9a9a9;">,</span><br /><span style="color:#008080;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [String]</span><span style="color:#ff4500;">$destination</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$PWD</span><span style="color:#a9a9a9;">,</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Connection</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$Global:ssh</span><span style="color:#a9a9a9;">,</span><br /><span style="color:#008080;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Switch]</span><span style="color:#ff4500;">$force</span><br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )</span><br /><span style="color:#00008b;">process</span> <span style="color:#000000;">{ </span><span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$Connection</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">server</span> <span style="color:#a9a9a9;">-and</span> <span style="color:#ff4500;">$Connection</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Credential</span> <span style="color:#a9a9a9;">-and</span> <span style="color:#ff4500;">$path</span> <span style="color:#000000;">)</span> <span style="color:#000000;">{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;<span style="color:#006400;">#Because we re-make the connection in the Get-Sftp command we can pass an SSH object. </span><br /><span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; write-verbose</span> <span style="color:#8b0000;">"Copying $path from $($Connection.Server) to $destination"</span><br /><span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Get-SFTP</span> <span style="color:#000080;">-RemoteFile</span> <span style="color:#ff4500;">$path</span> <span style="color:#000080;">-LocalFile</span> <span style="color:#ff4500;">$destination</span> <span style="color:#000080;">-Credential</span> <span style="color:#ff4500;">$Connection</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Credential</span> `<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000080;">-Server</span> <span style="color:#ff4500;">$Connection</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Server</span> <span style="color:#000080;">-Force</span> <span style="color:#000080;">-Overwrite:</span><span style="color:#ff4500;">$force</span> <span style="color:#a9a9a9;">|</span> <br /><span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Add-Member</span> <span style="color:#000080;">-PassThru</span> <span style="color:#000080;">-MemberType</span> <span style="color:#8a2be2;">Noteproperty</span> <span style="color:#000080;">-Name</span> <span style="color:#8b0000;">"Destination"</span> <span style="color:#000080;">-Value</span> <span style="color:#ff4500;">$destination</span><br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="color:#00008b;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Else</span> <span style="color:#000000;">{</span><span style="color:#0000ff;">Write-warning</span> <span style="color:#8b0000;">"We don't seem to have a valid destination and path"</span> <span style="color:#000000;">}</span><br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="color:#000000;">}</span><br /><span style="color:#0000ff;">Set-Alias</span> <span style="color:#000080;">-Name</span> <span style="color:#8a2be2;">rCopy</span> <span style="color:#000080;">-Value</span> <span style="color:#8a2be2;">Copy-RemoteItem</span></p>
<p><span style="color:#00008b;">Function</span> <span style="color:#8a2be2;">Copy-LocalItem</span> <span style="color:#000000;">{</span><br /><span style="color:#a9a9a9;">[</span><span style="color:#add8e6;">CmdletBinding</span><span style="color:#000000;">(</span><span style="color:#000000;">SupportsShouldProcess</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]</span><br /><span style="color:#00008b;">param</span> <span style="color:#000000;">(</span><span style="color:#a9a9a9;">[</span><span style="color:#add8e6;">Parameter</span><span style="color:#000000;">(</span><span style="color:#000000;">ValueFromPipeLine</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#a9a9a9;">,</span> <span style="color:#000000;">ValueFromPipelineByPropertyName</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#a9a9a9;">,</span> <span style="color:#000000;">mandatory</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]<br /></span><span style="color:#008080;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [String]</span><span style="color:#ff4500;">$path</span><span style="color:#a9a9a9;">,</span><br /><span style="color:#a9a9a9;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [</span><span style="color:#add8e6;">Parameter</span><span style="color:#000000;">(</span><span style="color:#000000;">Mandatory</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]</span><span style="color:#008080;">[String]</span><span style="color:#ff4500;">$destination</span><span style="color:#a9a9a9;"> </span><span style="color:#a9a9a9;">,</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Connection</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$Global:ssh</span><span style="color:#a9a9a9;">,</span><br /><span style="color:#008080;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Switch]</span><span style="color:#ff4500;">$force</span><br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )</span><br /><span style="color:#00008b;">process</span> <span style="color:#000000;">{</span>&nbsp; <span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$Connection</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">server</span> <span style="color:#a9a9a9;">-and</span> <span style="color:#ff4500;">$Connection</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Credential</span> <span style="color:#a9a9a9;">-and</span> <span style="color:#ff4500;">$path</span> <span style="color:#000000;">)</span> <span style="color:#000000;">{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#0000ff;">write-verbose</span> <span style="color:#8b0000;">"Copying $path to $destination on $($Connection.Server)"</span><br /><span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Send-SFTP</span> <span style="color:#000080;">-LocalFile</span> <span style="color:#ff4500;">$path</span> <span style="color:#000080;">-RemoteFile</span> <span style="color:#ff4500;">$destination</span> <span style="color:#000080;">-Credential</span> <span style="color:#ff4500;">$Connection</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Credential</span> `<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000080;">-Server</span> <span style="color:#ff4500;">$Connection</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Server</span> <span style="color:#000080;">-Force</span> <span style="color:#000080;">-Overwrite:</span><span style="color:#ff4500;">$force</span><br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="color:#00008b;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Else</span> <span style="color:#000000;">{</span><span style="color:#0000ff;">Write-warning</span> <span style="color:#8b0000;">"We don't seem to have a valid destination and path"</span> <span style="color:#000000;">}</span><br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="color:#000000;">}</span></code></p>
<p>The last wrapper I needed was one to go round Invoke-SSH – primarily to set default parameters, and return only the response text. </p>
<p>&nbsp;<code><span style="color:#00008b;">Function</span> <span style="color:#8a2be2;">Invoke-RemoteCommand</span> <span style="color:#000000;">{</span><br /><span style="color:#a9a9a9;">[</span><span style="color:#add8e6;">CmdletBinding</span><span style="color:#000000;">(</span><span style="color:#000000;">SupportsShouldProcess</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]</span><br /><span style="color:#00008b;">param</span>&nbsp;&nbsp; <span style="color:#000000;">(</span><span style="color:#a9a9a9;">[</span><span style="color:#add8e6;">parameter</span><span style="color:#000000;">(</span><span style="color:#000000;">Mandatory</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true </span><span style="color:#000000;">, <span style="color:#000000;">ValueFromPipeLine</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#000000;">)</span></span><span style="color:#a9a9a9;">]</span><span style="color:#008080;">[String]</span><span style="color:#ff4500;">$CmdLine</span><span style="color:#a9a9a9;">,</span><br /><span style="color:#a9a9a9;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#ff4500;">$Connection</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$Global:ssh</span><br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )</span><br /><span style="color:#00008b;">process</span> <span style="color:#000000;">{ </span><span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$Connection</span> <span style="color:#a9a9a9;">-is</span> <span style="color:#008080;">[PowerShellInside.NetCmdlets.Commands.SSHConnection]</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span> <br /><span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; write-verbose</span> <span style="color:#8b0000;">"# $cmdline"</span><br /><span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke-SSH</span> <span style="color:#000080;">-Connection</span> <span style="color:#ff4500;">$Connection</span> <span style="color:#000080;">-Command</span> <span style="color:#ff4500;">$CmdLine</span> <span style="color:#a9a9a9;">|<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;<span style="color:#0000ff;">Select-Object</span> <span style="color:#000080;">-ExpandProperty</span> <span style="color:#8a2be2;">text</span><br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span> <br /><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="color:#000000;">}</span></p>
<p>Job done … well almost. I’ll talk about a couple of tricks I’ve used in combination with these in future posts. </code></p>
<p><code></p>
<p></code></p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/powershell/'>Powershell</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1760/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1760/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1760/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1760/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1760/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1760/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1760/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1760/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1760/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1760/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1760/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1760/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1760/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1760/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1760&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/08/23/enhancing-the-netcmdlets/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>
	</item>
		<item>
		<title>Easy-formating for PowerShell with New-TableFormat</title>
		<link>http://jamesone111.wordpress.com/2011/08/22/easy-formating-for-powershell-with/</link>
		<comments>http://jamesone111.wordpress.com/2011/08/22/easy-formating-for-powershell-with/#comments</comments>
		<pubDate>Mon, 22 Aug 2011 10:09:39 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Powershell]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/2011/08/22/easy-formating-for-powershell-with/</guid>
		<description><![CDATA[Most of the PowerShell I write ends up as Functions: rather than scripts and it’s worth differentiating&#160; between the two. A function is something which can be called from somewhere else. A script is carries out a particular task (which might be to define some function(s) , or might be done with functions ) Several [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1758&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Most of the PowerShell I write ends up as <em>Functions</em>: rather than <em>scripts </em>and it’s worth differentiating&nbsp; between the two.
<ul>
<li>A function is something which can be called from somewhere else.
<li>A script is carries out a particular task (which might be to define some function(s) , or might be done <em>with </em>functions ) </li>
</ul>
<p>Several of my <a href="http://jamesone111.wordpress.com/2011/04/10/ten-tips-for-better-powershell-functions/">10 tips for better functions</a> are about being smart with inputs and outputs (which is less important for one off scripts). I should have included an extra point <strong>&#8220;Ask if constants should really be defaults for parameters&#8221; </strong>. If I notice &#8220;I am solving one specific case of X, with a value set to Y, so I can solve other X-problems if I allow the value to be changed.&#8221; it makes something reusable out of a one-off. For example, I put a wrapper round PowerShells great &#8220;Select-String&#8221; cmdlet to search PS1 files , then I realised that I might want to search .SQL or .XML files, but usually it would be PS1. So &#8220;*.PS1&#8243; became the default value for a -include parameter.
<p>Recently I put together a simple function named <strong>Get-SQL – </strong>it uses ODBC to send SQL commands – in&nbsp; my case to MySQL on a Linux box but it could be any ODBC source. To avoid constantly creating and tearing sessions, it saves an ODBCconnection object in a global variable between invocations . Once it has been run for the first time in a session I can type <strong>Get-SQL</strong> &#8220;command&#8221; and use the existing connection: and I’ve made sure SQL statements can be piped in (that’s what I mean by being smart about inputs).
<p>In it&#8217;s basic form Get-SQL takes 3 parameters, a connection string ($connection) a SQL statement ($SQL) and -ForceNew switch, which remakes the connection if it already exists <br /><code><span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$forceNew</span> <span style="color:#a9a9a9;">-or</span> <span style="color:#000000;">(</span><span style="color:#a9a9a9;">-not</span> <span style="color:#ff4500;">$global:ODBCconn</span><span style="color:#000000;">)</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp; $global:ODBCconn</span> <span style="color:#a9a9a9;">=</span> <span style="color:#0000ff;">New-Object</span> <span style="color:#8a2be2;">System.Data.Odbc.OdbcConnection</span><span style="color:#000000;">(</span><span style="color:#ff4500;">$connection</span><span style="color:#000000;">)</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp; $global:ODBCconn</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">open</span><span style="color:#000000;">(</span><span style="color:#000000;">)</span><br /><span style="color:#000000;">}</span><br /><span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$sql</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp; $adapter</span> <span style="color:#a9a9a9;">=</span> <span style="color:#0000ff;">New-Object</span> <span style="color:#8a2be2;">system.Data.Odbc.OdbcDataAdapter</span><span style="color:#000000;">(</span><br /><span style="color:#0000ff;">&nbsp;&nbsp;&nbsp; New-Object</span> <span style="color:#8a2be2;">system.Data.Odbc.OdbcCommand</span><span style="color:#000000;">(</span><span style="color:#ff4500;">$sql</span><span style="color:#a9a9a9;">,</span><span style="color:#ff4500;">$ODBCconn</span><span style="color:#000000;">)</span><span style="color:#000000;">)</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp; $table</span> <span style="color:#a9a9a9;">=</span> <span style="color:#0000ff;">New-Object</span> <span style="color:#8a2be2;">system.Data.datatable</span><br /><span style="color:#008080;">&nbsp;&nbsp;&nbsp; [void]</span><span style="color:#ff4500;">$adapter</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">fill</span><span style="color:#000000;">(</span><span style="color:#ff4500;">$table</span><span style="color:#000000;">)</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp; $table</span> <br /><span style="color:#000000;">}</span><br /><span style="color:#00008b;">else</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000000;">{</span><span style="color:#ff4500;">$ODBCconn</span> <span style="color:#000000;">}</span><br /></code>
<p>So, if a SQL statement is passed, any data rows it generates will be returned; but if I am just setting up a connection for the rest of my session the ODBC connection object is returned. <code>
<p>PS C:\Users\james\Documents\windowsPowershell&gt; Get-SQL -connection "DSN=foo-Customer5" <br />ConnectionString&nbsp; : DSN=foo-Customer5 <br />ConnectionTimeout : 15 <br />Database&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : foo <br />DataSource&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 192.168.1.234 via TCP/IP <br />ServerVersion&nbsp;&nbsp;&nbsp;&nbsp; : 5.0.77 <br />Driver&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : myodbc5.dll <br />State&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : Open <br />Site&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : <br />Container&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :
<p></code>
<p><strong>I <u>want</u> to show something shorter and simpler:</strong> I could finish with <br /><code>$ODBCConn | format-table DataSource , Database, State</code><br />that might be acceptable <em>now</em>, but I don&#8217;t know what problems I&#8217;m storing up for the future by not returning the full ODBC object. <br />The better option is to write a <strong>Formatting XML</strong> file – so the object remains the same but PowerShell <strong>displays</strong> it the way I want. But writing and debugging the XML longhand is tedious. So the temptation is to go with the <code>format-table</code> method and fix things up later; but there is a short-cut to writing the XML which avoids parking the problem for later.. <a href="http://richardspowershellblog.wordpress.com/2011/04/30/powershell-deep-dive-iv-formatting-script/">Richard mentions that it came up during the PowerShell Deep Dive in Vegas,</a> And I <a href="http://jtruher3.wordpress.com/2011/04/19/a-tool-for-table-formatting/">downloaded it from here.</a>&nbsp; (Slightly oddly you need to put <code>Function New-TableFormat { }</code> into the editor, and paste the code block in then run it)
<p>To use it you get the output the way you want with <code>Format-Table </code>and then replace &#8220;Format-Table&#8221; in the command line with <code>New-TableFormat</code> (with a couple of extra bits of finesse if needed). So it took about a minute to get the ODBC connection&nbsp; to display like this <code>
<p>Data Source&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Database State <br />-----------&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -------- ----- <br />192.168.1.234 via TCP/IP&nbsp;&nbsp; foo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Open</code>&nbsp;&nbsp;
<p>I&#8217;ve also created wrappers around <a href="http://powershellinside.com/powershell/netcmdlets/">/n software&#8217;s Netcmdlets</a> to make it easier to work with the linux server, and in one of those&nbsp; I call <br /><code>Connect-SSH -Server $server -Credential $credential -Force</code><br />which would normally output this : <code>
<p>AuthMode&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : Password <br />CertPassword&nbsp;&nbsp;&nbsp;&nbsp; :<br />CertStore&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : MY <br />CertStoreType&nbsp;&nbsp;&nbsp; : User <br />CertSubject&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : <br />Config&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : <br />Credential&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : System.Management.Automation.PSCredential <br />FirewallHost&nbsp;&nbsp;&nbsp;&nbsp; : <br />FirewallPassword : <br />FirewallPort&nbsp;&nbsp;&nbsp;&nbsp; : 0 <br />FirewallType&nbsp;&nbsp;&nbsp;&nbsp; : None <br />FirewallUser&nbsp;&nbsp;&nbsp;&nbsp; : <br />Force&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : True <br />LocalIP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :<br />Password&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : <br />Port&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 22 <br />Server&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 192.168.1.234 <br />ShellPrompt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : <br />SSHAccept&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : <br />Timeout&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 10 <br />User&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : </code></p>
<p>It took about Two minutes to get <code>Add-Member</code> to show what the host thinks its name is, and create a formatting XML file to get the result to look like this: <code>
<p>Connected to&nbsp;&nbsp; Port&nbsp; Host name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; User name <br />------------&nbsp;&nbsp; ----&nbsp; ---------&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --------- <br />192.168.4.71&nbsp;&nbsp; 22&nbsp;&nbsp;&nbsp; foo.contoso.com&nbsp; \root </code>
<p>It was all of another minute to create a manifest file to load my scripts &amp; formatting XML as a PowerShell module and have everything neat and tidy. Cracking stuff</p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/powershell/'>Powershell</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1758/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1758/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1758/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1758/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1758/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1758/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1758/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1758/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1758/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1758/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1758/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1758/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1758/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1758/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1758&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/08/22/easy-formating-for-powershell-with/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>
	</item>
		<item>
		<title>Adding &#8220;Out-Edit&#8221; functionality to PowerShell</title>
		<link>http://jamesone111.wordpress.com/2011/08/17/adding-out-edit-functionality-to-powershell/</link>
		<comments>http://jamesone111.wordpress.com/2011/08/17/adding-out-edit-functionality-to-powershell/#comments</comments>
		<pubDate>Wed, 17 Aug 2011 20:41:06 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Powershell]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/2011/08/17/adding-out-edit-functionality-to-powershell/</guid>
		<description><![CDATA[Back in March I wrote about useful bits in my PowerShell profile. Recently I’ve wanted to take the results of what I’m doing into an editor. It’s easy enough to pipe a result into CLIP.EXE which puts it in the clipboard, but it’s not too hard to use the object model of PowerShell ISE to [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1757&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Back <a href="http://jamesone111.wordpress.com/2011/03/21/whats-in-my-powershell-profile-2-edit/">in March</a> I wrote about useful bits in my PowerShell profile. Recently I’ve wanted to take the results of what I’m doing into an editor. It’s easy enough to pipe a result into <code>CLIP.EXE</code> which puts it in the clipboard, but it’s not too hard to use the object model of PowerShell ISE to do it directly.&nbsp; </p>
<p><code><span style="color:#00008b;">Function</span> <span style="color:#8a2be2;">Out-Edit</span> <span style="color:#000000;">{</span> <br />&nbsp; <span style="color:#00008b;">Param</span>&nbsp;&nbsp; <span style="color:#000000;">(</span> <span style="color:#a9a9a9;">[</span><span style="color:#add8e6;">parameter</span><span style="color:#000000;">(</span><span style="color:#000000;">ValueFromPipeLine</span><span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$true</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]</span><span style="color:#a9a9a9;">[</span><span style="color:#add8e6;">Alias</span><span style="color:#000000;">(</span><span style="color:#8b0000;">'Text'</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]</span><span style="color:#ff4500;">$inputObject</span><span style="color:#a9a9a9;">,</span>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#008080;">[String]</span><span style="color:#ff4500;">$Before</span><span style="color:#a9a9a9;">,</span> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#008080;">[String]</span><span style="color:#ff4500;">$After</span><span style="color:#a9a9a9;">,</span> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#008080;">[Switch]</span><span style="color:#ff4500;">$New</span> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000000;">)</span> <br /></code><code><span style="color:#00008b;">&nbsp;&nbsp; begin</span>&nbsp;&nbsp; <span style="color:#000000;">{</span> <span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$new</span><span style="color:#000000;">)</span>&nbsp;&nbsp; <span style="color:#000000;">{</span><span style="color:#ff4500;">$Editor</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$psise</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">CurrentPowerShellTab</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Files</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Add</span><span style="color:#000000;">(</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">editor</span> <span style="color:#000000;">}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;&nbsp; <span style="color:#00008b;">else</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000000;">{</span><span style="color:#ff4500;">$Editor</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$psise</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">CurrentFile</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Editor</span> <span style="color:#000000;">}</span> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$before</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span><span style="color:#ff4500;">$Editor</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">InsertText</span><span style="color:#000000;">(</span><span style="color:#ff4500;">$before</span><span style="color:#000000;">)</span> <span style="color:#000000;">}</span>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000000;">}<br /></span>&nbsp;&nbsp; <span style="color:#00008b;">process</span> <span style="color:#000000;">{</span> <span style="color:#ff4500;">$Editor</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">InsertText</span><span style="color:#000000;">(</span><span style="color:#ff4500;">$inputObject</span> <span style="color:#000000;">)</span> <span style="color:#000000;">}</span> <br /><span style="color:#00008b;">&nbsp;&nbsp; end</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000000;">{</span> <span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$after</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span><span style="color:#ff4500;">$Editor</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">InsertText</span><span style="color:#000000;">(</span><span style="color:#ff4500;">$after</span><span style="color:#000000;">)</span> <span style="color:#000000;">}</span> <span style="color:#000000;">}</span> <br /><span style="color:#000000;">}</span></code></p>
<p>I gave the function a <code>–new</code> switch to decide if the input goes into the current file or a new one. And to allow the input to be topped and tailed – typically with something like <code>$Foo=@"</code> and <code>"@ </code>to make my output into a <a href="http://technet.microsoft.com/en-us/library/ee692792.aspx">here-string</a> , it’s just a case of getting a new or current file’s editor and calling its <code>.InsertText()</code> method</p>
<p><strong>Note: </strong>In that March piece I showed my replacement for the default PSEDIT function, in the end I merged it with the function above and I’ve put my profile.ps1 on <a href="https://skydrive.live.com/?cid=1efe2682bfbbd817&amp;sc=documents&amp;id=1EFE2682BFBBD817%211806">skydrive</a>. In the end I changed the NEW switch, to a “UseExisting” switch, because I found that I almost always needed the new option. </p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/powershell/'>Powershell</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1757/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1757/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1757/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1757/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1757/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1757/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1757/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1757/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1757/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1757/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1757/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1757/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1757/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1757/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1757&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/08/17/adding-out-edit-functionality-to-powershell/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>
	</item>
		<item>
		<title>Prayer-based parsing: PowerShell regular expressions again.</title>
		<link>http://jamesone111.wordpress.com/2011/08/07/prayer-based-parsing-powershell-regular-expressions-again/</link>
		<comments>http://jamesone111.wordpress.com/2011/08/07/prayer-based-parsing-powershell-regular-expressions-again/#comments</comments>
		<pubDate>Sun, 07 Aug 2011 09:52:35 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Powershell]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/2011/08/07/prayer-based-parsing-powershell-regular-expressions-again/</guid>
		<description><![CDATA[&#160; Recently I saw a quote on Scott Hanselman’s blog You&#8217;ve got a problem, and you&#8217;ve decided to use regular expressions to solve it.Ok, now you&#8217;ve got two problems&#8230;&#8221; A telling of the history of this Quote provides some other good quotes,; some restate “Using X as a solution adds to the problems”&#160; another expanded [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1755&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>&nbsp;
<p>Recently I saw a quote on <a href="http://www.hanselman.com/blog/UnixFightSedGrepAwkCutAndPullingGroupsOutOfAPowerShellRegularExpressionCapture.aspx">Scott Hanselman’s blog</a><br />
<blockquote>
<p><em><strong>You&#8217;ve got a problem, and you&#8217;ve decided to use regular expressions to solve it.<br /></strong></em><em><strong>Ok, now you&#8217;ve got two problems&#8230;&#8221;</strong></em></p>
</blockquote>
<p><a href="http://regex.info/blog/2006-09-15/247">A telling of the history of this Quote</a> provides some other good quotes,; some restate “Using X as a solution adds to the problems”&nbsp; another expanded a point I heard <a href="http://tfl09.blogspot.com/">Thomas Lee</a> make at one of his PowerShell camps. In PowerShell you can pipe a folder <em>object</em>, or a process <em>object</em> between steps and get its name from a .name <em>property</em>. Without this model: as one of quotes puts it: </p>
<blockquote><p><em><strong>The decades-old Unix “pipe” model is just plain dumb, because it forces you to think of everything as serializable text, even things that are fundamentally not text, or that are not sensibly serializable</strong></em></p>
</blockquote>
<p>(DOS copied the Unix pipe model, and it’s still in Windows -away from PowerShell).<br />Thomas had a great term for <em>de-serializing</em> text: <strong>“Prayer based parsing”</strong>. Every time you extract the bits you want from the text, you need to pray that it (still) works with your parsing rules. Some of the more arcane switches for command-line tools (on whatever OS) are to control their output – with one eye on simplifying the job of parsing it.&nbsp;
<p>Some tasks –like&nbsp; “Screen scraping” – leave no alternative but to parse text. (<strong> “A text only “pipe” is just automated screen scraping”</strong> is another way to describe the problem PowerShell’s pipeline solves.) Regular expressions are <em>“big hammer”</em> for advanced parsing (some of the “quotes” article gets into whether in Perl they are the <em>most suitable</em> hammer , or the <em>most obvious</em> hammer), and they’re something which PowerShell handles deftly with the –match and –replace operators.
<p>I recently wanted to take a list of companies offering training which I had found the web, and transform it into a more database like format. In my screen scraped list each company had an entry which looked like this<br />
<blockquote>
<p>Contoso Ltd S-1234<br />123 Station Road<br />Aberdeen<br />AB12 3DE<br />info@Contoso.com<br />http://www.contoso.com<br />Ph: (44) 123-456789<br />Fax: (44) 123-456790
<p>Sign Up for a Online Course
<p>approx: 0.8km / 0.5mi from London, GB, United Kingdom</p>
</blockquote>
<p>I copied the list, and opened a new tab the PowerShell ISE and created a small snippet of PowerShell <br /><code><span style="color:#ff4500;">$list</span> <span style="color:#a9a9a9;">=</span> <span style="color:#8b0000;">@"</p>
<p>"@</span> </code></p>
<p>The @&#8221; … &#8220;@&nbsp; defines a multi-line “<a href="http://en.wikipedia.org/wiki/Here_document#Windows_PowerShell">here-string</a>” – so I can paste the data in between the quotes hit the <em>Run Script</em> button and ta-da! my list is in a PowerShell variable. Studying the format, all the data I want is on consecutive lines – with a double line space after them. The –replace operator can remove single line breaks, leaving additional ones, to group the text I want on one line. <br /><code><strong>$list -replace "\r\n(?=\w)", ", " <br /></strong></code>\r and \n indicate the return and newline characters. So <code>-replace "\r\n", ", "</code> would replace all line breaks with with a comma and a space,<br />the (?=&nbsp; ) construction specifies a “look ahead” says “<strong>match ONLY if what you have found is followed by…</strong>” and I want the replacement to happen only if the return/newline is followed by a ‘word’ character (\w) – so a line break followed by another line break won’t be replaced. </p>
<p>Now I can split my list – which is still a single giant string into&nbsp; into multiple strings. Where I had two line breaks I know have one line break, a comma and a space so I can use that as the expression for the –split operator.&nbsp; <br /><code>($list -replace "\r\n(?=\w)", ", ") <strong><u>-split "\r\n, "</u> </strong></code></p>
<p>So far so good, but this will give be distances and the call to take a course. I want to discard any lines which don’t contain a company’s ID number </p>
<p><code>($list -replace "\r\n(?=\w)", ", ") -split "\r\n, " <strong>|<br />&nbsp;&nbsp;&nbsp; <u>foreach { if ($_ -match "\ss-\d+\s*,") {'"' + $_ + '"'}} </u></strong></code></p>
<p>This looks at each line and if it contains a space, ‘S’, ‘–’, at least one digit, any number of spaces (including zero) and then a comma, it returns the line wrapped in double quotes. So now my text is one line per company looking like this.&nbsp; </p>
<p><em>&#8220;Contoso Ltd S-1234, 123 Station Road, Aberdeen, AB12 3DE, info@Contoso.com, http://www.contoso.com, Ph: (44) 123-456789 , Fax: (44) 123-456790&#8243; </em>
<p>My next step is to replace the space <em>before</em> the ID number with ‘ &#8220;,&#8221; ’&nbsp;
<p><code>(($list -replace "`r`n(?=\w)", ", ") -split "`r`n, " |<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach { if ($_ -match "\ss-\d+\s*,") {'"' + $_ + '"'}} <br />)<strong> <u>-replace "\s+(?=S-\d+\s*,)", '","'</u> </strong></code></p>
<p><code>"\s+(?=S-\d+\s*,)"</code> says <strong>“match on one or more spaces ONLY IF&nbsp; <em>followed</em> by S, –, at least one digit, any spaces (or none) and then a comma.”</strong>&nbsp; Wherever that Occurs I insert &#8220;,&#8221; breaking my line into two quoted strings separated by a comma – just like a CSV file.&nbsp; The next step is to make it three quoted strings by replacing the coma and spaces <em>after</em> the ID number with the same ‘ &#8220;,&#8221; ’&nbsp; combination</p>
<p><code>(($list -replace "`r`n(?=\w)", ", ") -split "`r`n, " |<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach { if ($_ -match "\ss-\d+\s*,") {'"' + $_ + '"'}} <br />) -replace "\s+(?=S-\d+\s*,)", '","'<strong>&nbsp; <u>-replace "(?&lt;=S-\d+),\s*",'","'</u></strong></code></p>
<p><code>"(?&lt;=S-\d+),\s*"</code> uses&nbsp; (?&lt;=&nbsp;&nbsp; ) which is the look-behind construction, saying&nbsp; <strong>“match on comma <em>and</em> any spaces (or none) ONLY IF it is <em>preceded</em> by ‘S’, ‘–’ and at least one digit”</strong>.&nbsp; Now my line looks like this</p>
<p><em>&#8220;Contoso Ltd<u>”,”</u>S-1234<u>”,”</u>123 Station Road, Aberdeen, AB12 3DE, info@Contoso.com, http://www.contoso.com, Ph: (44) 123-456789 , Fax: (44) 123-456790&#8243; </em></p>
<p>The next task is to put the &#8221; , &#8221; combination before an email address: </p>
<p><code>(($list -replace "`r`n(?=\w)", ", ") -split "`r`n, " |<br />foreach { if ($_ -match "\ss-\d+\s*,") {'"' + $_ + '"'}} <br />) -replace "\s+(?=S-\d+\s*,)", '","'<strong> </strong>-replace "(?&lt;=S-\d+),\s*",'","' `<br /><u><strong>–replace <code>",\s* (?=\w+@\w+\.\w+)"</code> ,'","'</strong></u></code>
<p><code>",\s* (?=\w+@\w+\.\w+)"</code> says<strong> “match on comma and any spaces ONLY IF followed by at least one character , an @ sign, at least one character , a dot, and at least one character.”</strong><br />Then I can use&nbsp; <code>",\s*(?=http)"</code> which matches on comma and any spaces ONLY IF followed by <em>http</em> and finally <code>"\s*,\s* Ph:\*"</code> and <code>"\s*,\s*Fax:\s* "</code> match on the ph and fax tags and surrounding spaces to put &#8220;,&#8221; before each of those. </p>
<p>Instead of using a different <code>–replace</code> operation for each step the terms&nbsp; can be condensed into a <strong>single expression with | for “or” between each part.</strong>&nbsp; You can see that building the expression up bit by bit is a lot easier than writing it in one go. </p>
<p><code>(($list -replace "`r`n(?=\w)", ", ") -split "`r`n, " | <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach { if ($_ -match "\ss-\d+\s*,") {'"' + $_ + '"'}} <br />) <u>-replace <strong>"\s+(?=S-\d+\s*,)|(?&lt;=S-\d+),\s*|, (?=\w+@\w+\.\w+)|,\s* (?=http)|\s*,\s*Ph:\s*|\s*,\s*Fax:\s*" </strong>, '","' </u></code></p>
<p>This turns my text into </p>
<p><em>&#8220;Contoso&nbsp; Ltd&#8221;,&#8221;S-1234&#8243;,&#8221;123 Station Road, Aberdeen, AB12 3DE&#8221;, &#8220;info@Contoso.com&#8221;,&#8221;http://www.contoso.com&#8221;,&#8221;(44) 123-456789&#8243;,&#8221;(44) 123-456790&#8243;<br /></em></p>
<p>There is potentially more-cleaning up I could do – for example identifying lines without email or URL sections and inserting a blank &#8220;&#8221;, in their place. But this gives me all I need; by writing a header row to a file and adding and my text to it I would get a ready made CSV file for Excel. I could have turned it into a bulk database import or used PowerShell’s has a <code>ConvertFrom-Csv</code> cmdlet to turn each row into a object or any number of other things. I don’t think I would have tried typing that line in one go: but PowerShell induced the habit of building up these long lines a little at a time meant it only took a couple of minutes to do.&nbsp; </p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/powershell/'>Powershell</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1755/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1755/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1755/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1755/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1755/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1755/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1755/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1755/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1755/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1755/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1755/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1755/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1755/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1755/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1755&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/08/07/prayer-based-parsing-powershell-regular-expressions-again/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>
	</item>
		<item>
		<title>A &#8220;Tail&#8221; command in PowerShell</title>
		<link>http://jamesone111.wordpress.com/2011/07/27/a-tail-command-in-powershell/</link>
		<comments>http://jamesone111.wordpress.com/2011/07/27/a-tail-command-in-powershell/#comments</comments>
		<pubDate>Wed, 27 Jul 2011 15:46:27 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Powershell]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/2011/07/27/a-tail-command-in-powershell/</guid>
		<description><![CDATA[I mentioned that I have been working for a small Software company and in this new role I’m having to work with Linux servers and MySQL. MySQL has proved rather better than I expected and Linux itself worse –at least from the perspective of being place for me to get work done (I’ll leave the [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1749&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I mentioned that I have been working for a small Software company and in this new role I’m having to work with Linux servers and MySQL. MySQL has proved rather better than I expected and Linux itself <em>worse</em> –at least from the perspective of being place for me to get work done (I’ll leave the reasons why for another time).&nbsp; Our app generates quite a lot of log files, and so do some of the services it uses , and so most of time I’ll have at least one Window open running the Unix <code>tail –f</code> command (tail outputs the last few lines from a file, and <code>–f</code> tells it to <em>follow</em> the file –that is, to keep watching it and output anything added to it).&nbsp; There should be one for Windows but a quick search didn’t turn one up – so I put one together with PowerShell which pulls some interesting techniques from more than one place. </p>
<h3>Watching a file</h3>
<p>The first thing that’s needed to give the follow functionality is the ability to know when the log file has changed. I found that James Brundage’s <a href="http://archive.msdn.microsoft.com/PowerShellPack">PowerShell Pack</a> gave me ALMOST what I needed. Here’s my modified version</p>
<p><code><span style="color:#00008b;">Function</span> <span style="color:#8a2be2;">Register-FileSystemWatcher</span> <span style="color:#000000;">{<br /></span><span style="color:#00008b;">param</span><span style="color:#000000;">(</span>&nbsp; <span style="color:#a9a9a9;">[</span><span style="color:#add8e6;">Parameter</span><span style="color:#000000;">(</span><span style="color:#000000;">ValueFromPipelineByPropertyName</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#a9a9a9;">,</span><span style="color:#000000;">Position</span><span style="color:#a9a9a9;">=</span><span style="color:#800080;">0</span><span style="color:#a9a9a9;">,</span><span style="color:#000000;">Mandatory</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$true</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;<span style="color:#a9a9a9;">[</span><span style="color:#add8e6;">Alias</span><span style="color:#000000;">(</span><span style="color:#8b0000;">'FullName'</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]</span> <span style="color:#008080;">[string]</span><span style="color:#ff4500;">$Path</span><span style="color:#a9a9a9;">,</span> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#008080;">[string]</span><span style="color:#ff4500;">$Filter</span> <span style="color:#a9a9a9;">=</span> <span style="color:#8b0000;">"*"</span><span style="color:#a9a9a9;">,</span> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#008080;">[switch]</span><span style="color:#ff4500;">$Recurse</span><span style="color:#a9a9a9;">,</span>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#a9a9a9;">[</span><span style="color:#add8e6;">Alias</span><span style="color:#000000;">(</span><span style="color:#8b0000;">'Do'</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">]</span><span style="color:#008080;">[ScriptBlock[]]</span><span style="color:#ff4500;">$Process</span><span style="color:#a9a9a9;">,</span> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#ff4500;">$MessageData</span><span style="color:#a9a9a9;">,</span>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#008080;">[string[]]</span><span style="color:#ff4500;">$On</span> <span style="color:#a9a9a9;">=</span> <span style="color:#000000;">@(</span><span style="color:#8b0000;">"Created"</span><span style="color:#a9a9a9;">,</span> <span style="color:#8b0000;">"Deleted"</span><span style="color:#a9a9a9;">,</span> <span style="color:#8b0000;">"Changed"</span><span style="color:#a9a9a9;">,</span> <span style="color:#8b0000;">"Renamed"</span><span style="color:#000000;">)</span><span style="color:#000000;">)<br /></span> <span style="color:#00008b;">begin</span>&nbsp;&nbsp; <span style="color:#000000;">{</span> <span style="color:#ff4500;">$ValidEvents</span> <span style="color:#a9a9a9;">=</span> <span style="color:#008080;">[IO.FileSystemWatcher]</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">GetEvents</span><span style="color:#000000;">(</span><span style="color:#000000;">)</span> <span style="color:#a9a9a9;">|</span> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#0000ff;">select-object</span> <span style="color:#000080;">-ExpandProperty</span> <span style="color:#8a2be2;">name<br /></span><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span> <br /><span style="color:#00008b;">process</span> <span style="color:#000000;">{</span> <br />&nbsp;&nbsp;&nbsp; <span style="color:#ff4500;">$realItem</span> <span style="color:#a9a9a9;">=</span> <span style="color:#0000ff;">Get-Item</span> <span style="color:#000080;">-path</span> <span style="color:#ff4500;">$path</span> <span style="color:#000080;">-ErrorAction</span> <span style="color:#8a2be2;">SilentlyContinue</span> <br />&nbsp;&nbsp;&nbsp; </code><code><span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#a9a9a9;">-not</span> <span style="color:#ff4500;">$realItem</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span> <span style="color:#00008b;">return</span> <span style="color:#000000;">}</span> <br />&nbsp;&nbsp;&nbsp; <span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$realItem</span> <span style="color:#a9a9a9;">-is</span> <span style="color:#008080;">[system.io.fileinfo]</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#ff4500;">$Path </span><span style="color:#a9a9a9;">=</span> <span style="color:#0000ff;">Split-Path</span> <span style="color:#ff4500;">$realItem</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Fullname</span> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#ff4500;">$Filter</span> <span style="color:#a9a9a9;">=</span> <span style="color:#0000ff;">Split-Path</span> <span style="color:#ff4500;">$realItem</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Fullname</span> <span style="color:#000080;">-leaf</span> <span style="color:#000000;">}<br />&nbsp;&nbsp;&nbsp; </span><span style="color:#00008b;">else</span> <span style="color:#000000;">{</span> <span style="color:#ff4500;">$Path</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$realItem</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Fullname</span><span style="color:#000000;">}<br /></span>&nbsp;&nbsp;&nbsp; <span style="color:#ff4500;">$watcher</span> <span style="color:#a9a9a9;">=</span> <span style="color:#0000ff;">New-Object</span> <span style="color:#8a2be2;">IO.FileSystemWatcher</span> <span style="color:#000080;">-Property</span> <span style="color:#000000;">@{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#000000;">Path</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$path</span><span style="color:#000000;">;</span> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000000;">Filter</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$filter</span><span style="color:#000000;">;</span>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000000;">IncludeSubdirectories</span><span style="color:#a9a9a9;">=</span><span style="color:#ff4500;">$Recurse</span><span style="color:#000000;">}</span> <br />&nbsp;&nbsp;&nbsp; <span style="color:#00008b;">foreach</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$o</span> <span style="color:#00008b;">in</span> <span style="color:#ff4500;">$on</span><span style="color:#000000;">)</span> <span style="color:#000000;">{<br />&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;<span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$validEvents</span> <span style="color:#a9a9a9;">-Ccontains</span> <span style="color:#ff4500;">$o</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span> <span style="color:#006400;">#Note CASE SENSITIVE CONTAINS...<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#00008b;">foreach</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$p</span> <span style="color:#00008b;">in</span> <span style="color:#ff4500;">$process</span><span style="color:#000000;">)</span> <span style="color:#000000;">{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$p</span><span style="color:#000000;">)</span><span style="color:#000000;">{</span><span style="color:#0000ff;">Register-ObjectEvent</span> <span style="color:#ff4500;">$watcher</span> <span style="color:#ff4500;">$o</span> <span style="color:#000080;">-Action</span> <span style="color:#ff4500;">$d</span> <span style="color:#000080;">-MessageData</span> <span style="color:#ff4500;">$MessageData</span><span style="color:#000000;">}<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000000;">}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></code><code><span style="color:#000000;">}</span>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#00008b;">Else</span> <span style="color:#000000;">{</span><span style="color:#0000ff;">Write-warning</span> <span style="color:#000000;">(</span><span style="color:#8b0000;">"$o is an invalid event name and was ignored." <span style="color:#a9a9a9;">+<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#008080;">&nbsp;&nbsp;&nbsp;&nbsp; [Environment]</span><span style="color:#a9a9a9;">::</span><span style="color:#000000;">NewLine</span> <span style="color:#a9a9a9;">+</span> "Names are case sensitive and valid ones are" </span><span style="color:#a9a9a9;">+<br /></span><span style="color:#008080;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Environment]</span><span style="color:#a9a9a9;">::</span><span style="color:#000000;">NewLine</span> <span style="color:#a9a9a9;">+</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$ValidEvents</span> <span style="color:#a9a9a9;">-join</span> <span style="color:#8b0000;">", "</span><span style="color:#000000;">)</span> <span style="color:#a9a9a9;">+</span> <span style="color:#8b0000;">"."</span><span style="color:#000000;">)<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#000000;">}<br /></span>&nbsp;&nbsp;&nbsp; <span style="color:#000000;">}<br /></span><span style="color:#000000;">}<br /></span></code><code><span style="color:#000000;">}</span> </code></p>
<p>The Function takes a <code>path</code> (usually a folder but possibly a file which can be passed via the pipeline) a <code>filter</code>, and a <code>–recurse</code> switch which determine what to watch. If the path isn’t valid the function drops out, and if the path is a file it is split into <em>name</em> and <em>folder</em> parts – the name becomes the filter and the folder becomes the path. <br />The path, filter and recurse are used to create a <code>FileWatcher</code> object. A FileWatcher raises events , and <code>Register-ObjectEvent</code> hooks PowerShell up to these events: the cmdlet says “when <em>this</em> event happens on <em>that</em> object, run <em>this</em> code block”. Usefully &#8211; as I learnt from a post on <a href="//www.ravichaganti.com/blog/?p=2187">Ravikanth Chaganti’s blog</a> you can pass something to the registration for use later on – which I’ll come back to in when we see the function in use. I do a quick check to see the event passed is valid before trying to hook up the code to it, generating a warning. </p>
<p>The tail command I created is named <code>“Get-Tail”</code> for two reasons, <br />(a) What gets returned is the “tail of the file” so <code>GET-</code> is the right verb to use out of the standard ones <br />(b) If PowerShell can’t find a command <code>name</code> it tries <code>Get-Name</code> as an alias, in other words:<br />&nbsp;<code>Get-Tail</code> can be invoked simply as <code>tail</code>. It looks like this </p>
<p><code><span style="color:#00008b;">function</span> <span style="color:#8a2be2;">Get-tail</span> <span style="color:#000000;">{<br /></span><span style="color:#00008b;">param</span> <span style="color:#000000;">(</span> <span style="color:#ff4500;">$path</span><span style="color:#a9a9a9;">,</span> <br /><span style="color:#008080;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [int]</span><span style="color:#ff4500;">$Last</span> <span style="color:#a9a9a9;">=</span> <span style="color:#800080;">20</span><span style="color:#a9a9a9;">,</span> <br /><span style="color:#008080;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [int]</span><span style="color:#ff4500;">$CharsPerLine</span> <span style="color:#a9a9a9;">=</span> <span style="color:#800080;">500</span><span style="color:#a9a9a9;">,</span> <br /><span style="color:#008080;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Switch]</span><span style="color:#ff4500;">$follow</span> <br /></code><code><span style="color:#000000;">)</span> <br /></code><code><span style="color:#ff4500;">$item</span> <span style="color:#a9a9a9;">=</span> <span style="color:#000000;">(</span><span style="color:#0000ff;">Get-item</span> <span style="color:#ff4500;">$path</span><span style="color:#000000;">)</span> <br /></code><code><span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#a9a9a9;">-not</span> <span style="color:#ff4500;">$item</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span><span style="color:#00008b;">return</span><span style="color:#000000;">}</span> <br /><span style="color:#ff4500;">$Stream</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$item</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Open</span><span style="color:#000000;">(</span><span style="color:#008080;">[System.IO.FileMode]</span><span style="color:#a9a9a9;">::</span><span style="color:#000000;">Open</span><span style="color:#a9a9a9;">,</span> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#008080;">[System.IO.FileAccess]</span><span style="color:#a9a9a9;">::</span><span style="color:#000000;">Read</span><span style="color:#a9a9a9;">,</span>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#008080;">[System.IO.FileShare]</span><span style="color:#a9a9a9;">::</span><span style="color:#000000;">ReadWrite</span><span style="color:#000000;">)</span> <br /><span style="color:#ff4500;">$reader</span> <span style="color:#a9a9a9;">=</span> <span style="color:#0000ff;">New-Object</span> <span style="color:#8a2be2;">System.IO.StreamReader</span><span style="color:#000000;">(</span><span style="color:#ff4500;">$Stream</span><span style="color:#000000;">)</span> <br /><span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$charsPerLine</span> <span style="color:#a9a9a9;">*</span> <span style="color:#ff4500;">$last</span> <span style="color:#a9a9a9;">-lt</span> <span style="color:#ff4500;">$item</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">length</span><span style="color:#000000;">)</span> <span style="color:#000000;">{<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#ff4500;">$reader</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">BaseStream</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">seek</span><span style="color:#000000;">(</span><span style="color:#000000;">(</span><span style="color:#800080;">-1</span> <span style="color:#a9a9a9;">*</span> <span style="color:#ff4500;">$last</span> <span style="color:#a9a9a9;">*</span> <span style="color:#ff4500;">$charsPerLine</span><span style="color:#000000;">)</span> <span style="color:#a9a9a9;">,</span><span style="color:#008080;">[system.io.seekorigin]</span><span style="color:#a9a9a9;">::</span><span style="color:#000000;">End</span><span style="color:#000000;">)</span> <br /><span style="color:#000000;">}</span> <br /><span style="color:#ff4500;">$reader</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">readtoend</span><span style="color:#000000;">(</span><span style="color:#000000;">)</span> <span style="color:#a9a9a9;">-split</span> <span style="color:#8b0000;">"`n"</span> <span style="color:#a9a9a9;">-replace</span> <span style="color:#8b0000;">"\s+$"</span><span style="color:#a9a9a9;">,</span><span style="color:#8b0000;">""</span> <span style="color:#a9a9a9;">|</span> <span style="color:#0000ff;">Select-Object</span> <span style="color:#000080;">-last</span> <span style="color:#ff4500;">$Last</span> <span style="color:#a9a9a9;">|</span> <span style="color:#0000ff;">write-host<br /></span><span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$follow</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span><br /><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Global:watcher</span> <span style="color:#a9a9a9;">=</span> <span style="color:#0000ff;">Register-FileSystemWatcher</span> <span style="color:#000080;">-Path</span> <span style="color:#ff4500;">$path</span> <span style="color:#000080;">-MessageData</span> <span style="color:#ff4500;">$reader<span style="color:#000000;">` <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>&nbsp;<span style="color:#000080;">-On</span> <span style="color:#8b0000;">"Changed"</span> <span style="color:#000080;">-Process</span> <span style="color:#000000;">{<br /></span><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $event</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">MessageData</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">readtoend</span><span style="color:#000000;">(</span><span style="color:#000000;">)</span> <span style="color:#a9a9a9;">-split</span> <span style="color:#8b0000;">"`n"</span> <span style="color:#a9a9a9;">-replace</span> <span style="color:#8b0000;">"\s+$"</span><span style="color:#a9a9a9;">,</span><span style="color:#8b0000;">""</span> <span style="color:#a9a9a9;">|</span> <span style="color:#0000ff;">write-host</span> <span style="color:#000000;">}<br /></span><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $oldConsoleSetting</span> <span style="color:#a9a9a9;">=</span> <span style="color:#008080;">[console]</span><span style="color:#a9a9a9;">::</span><span style="color:#000000;">TreatControlCAsInput</span>&nbsp;<font color="#000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><span style="color:#008080;">[console]</span><span style="color:#a9a9a9;">::</span><span style="color:#000000;">TreatControlCAsInput</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$true</span> <br /><span style="color:#00008b;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$true</span><span style="color:#000000;">)</span> <span style="color:#000000;">{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#008080;">[console]</span><span style="color:#a9a9a9;">::</span><span style="color:#000000;">KeyAvailable</span><span style="color:#000000;">)</span> <span style="color:#000000;">{<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#ff4500;">$key</span> <span style="color:#a9a9a9;">=</span> <span style="color:#008080;">[system.console]</span><span style="color:#a9a9a9;">::</span><span style="color:#000000;">readkey</span><span style="color:#000000;">(</span><span style="color:#ff4500;">$true</span><span style="color:#000000;">)</span>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#000000;">(</span><span style="color:#ff4500;">$key</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">modifiers</span> <span style="color:#a9a9a9;">-band</span> <span style="color:#008080;">[consolemodifiers]</span><span style="color:#8b0000;">"control"</span><span style="color:#000000;">)</span> –<span style="color:#a9a9a9;">and<br /></span><span style="color:#000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (</span><span style="color:#ff4500;">$key</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">key</span> <span style="color:#a9a9a9;">-eq</span> <span style="color:#8b0000;">"C"</span><span style="color:#000000;">)</span><span style="color:#000000;">)</span> <span style="color:#000000;">{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;<span style="color:#0000ff;">write-host</span> <span style="color:#000080;">-ForegroundColor</span> <span style="color:#8a2be2;">red</span> <span style="color:#8b0000;">"Terminating..."</span> <span style="color:#000000;">;</span> <span style="color:#00008b;">break</span> <span style="color:#000000;">}</span>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#00008b;">else</span> <span style="color:#000000;">{</span> <span style="color:#00008b;">if</span> <span style="color:#000000;">(</span><span style="color:#008080;">[int]</span><span style="color:#ff4500;">$key</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">keyCHAR</span> <span style="color:#a9a9a9;">-eq</span> <span style="color:#800080;">13</span><span style="color:#000000;">)</span> <span style="color:#000000;">{</span> <span style="color:#008080;">[console]</span><span style="color:#a9a9a9;">::</span><span style="color:#000000;">WriteLine</span><span style="color:#000000;">(</span><span style="color:#000000;">)</span> <span style="color:#000000;">}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#00008b;">else</span> <span style="color:#000000;">{</span> <span style="color:#008080;">[console]</span><span style="color:#a9a9a9;">::</span><span style="color:#000000;">Write</span><span style="color:#000000;">(</span><span style="color:#ff4500;">$key</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">keyCHAR</span><span style="color:#000000;">)</span> <span style="color:#000000;">}</span><span style="color:#000000;">}</span> <span style="color:#000000;">}</span> <span style="color:#006400;"><br /></span><span style="color:#00008b;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else</span> <span style="color:#000000;">{</span><span style="color:#0000ff;">Start-Sleep</span> <span style="color:#000080;">-Milliseconds</span> <span style="color:#800080;">250</span><span style="color:#000000;">}</span> <span style="color:#000000;">}</span>&nbsp;<span style="color:#006400;"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></code><code><span style="color:#008080;">[console]</span><span style="color:#a9a9a9;">::</span><span style="color:#000000;">TreatControlCAsInput</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$oldConsoleSetting</span> <br /><span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Unregister-Event</span> <span style="color:#ff4500;">$watcher</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">name<br /></span>&nbsp;&nbsp; <span style="color:#000000;">}</span>&nbsp;<br /><span style="color:#ff4500;">$Stream</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Close</span><span style="color:#000000;">(</span><span style="color:#000000;">)</span>&nbsp;<br /><span style="color:#ff4500;">$reader</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Close</span><span style="color:#000000;">(</span><span style="color:#000000;">)</span> <br /><span style="color:#000000;">}</span> </code></p>
<h3>Opening a sharable file in PowerShell </h3>
<p>The function takes 4 parameters, <code>–path</code> , <code>-last</code> a <code>-follow</code> switch and a –<code>CharsPerLine </code>which was a bit of an after thought. : the <code>.Open()</code> method is used to open the file as a Read-Only <code>FileStream</code> allowing writes by others; and a <code>StreamReader</code> object is created to read from this Stream. </p>
<p>By using the Reader’s <code>.ReadToEnd()</code> method I could be ready to read anything which is added to the end of the file, and&nbsp; output the result splitting it on new lines and removing end-of-line spaces – all of which is not much than I could have done with <code>Get-Content</code>. <br />I added a refinement after realizing that I occasionally deal with log files which are over a Gigabyte in length. Not only will they take ages to read, but using <code>.ReadToEnd()</code> will try to read the whole file into memory which is just horrible. So I added a –<code>CharsPerLine </code>parameter – I multiply this by the number of lines I want to read and if the file is bigger than that I seek forward to that many bytes from the end the file, before calling <code>.ReadToEnd().</code> The default is a generous 500, so if I request 2000 lines I’ll read 1MB of data which isn’t too terrible even if the average line length is only a few characters. If I’m reading 20,000 lines I might set the parameter lower, or if I know the lines are very long I might set it higher. Then everything is set up for the optional <code>Follow</code> part. </p>
<h3>Who reads for the Watchers ? </h3>
<p>I want to call the <code>.ReadToEnd()</code> method when the file changes and output everything up to the end of the file. The question is, how to have access to the StreamReader inside the script which runs when FileSystemWatcher fires its <code>changed</code> event ? This is where <a href="//www.ravichaganti.com/blog/?p=2187">Ravikanth Chaganti’s tip</a> comes in; by making the Reader the “Message Object” for the event, it can be referenced in the script block.&nbsp; By the way because I don’t know what else might end up happening I force the output to the console throughout – though my normal custom is to avoid using <code><span style="color:#0000ff;"><font color="#000000">write-host</font></span></code><br /><code><span style="color:#000000;">{</span><span style="color:#ff4500;">$event</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">MessageData</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">readtoend</span><span style="color:#000000;">(</span><span style="color:#000000;">)</span> <span style="color:#a9a9a9;">-split</span> <span style="color:#8b0000;">"\s*`n"</span> <font color="#a9a9a9">| </font><span style="color:#0000ff;">write-host</span> <span style="color:#000000;">} <br /></span></code></p>
<p>Taking Control of Control+C</p>
<p>Finally – to mimic the behaviour of <code>tail</code> on unix I trap keyboard input and pass it through to the console until the user presses [Ctrl][c].&nbsp; This works much better in the “Shell” form of PowerShell than the ISE. When [Ctrl][c]. is pressed the function cleans up and exits. </p>
<p>Job done.&nbsp; </p>
<p><b>Update: I&#8217;ve put the script <a href="https://skydrive.live.com/?cid=1efe2682bfbbd817&amp;sc=documents&amp;uc=1&amp;id=1EFE2682BFBBD817%21133#">here for download</a> </b></p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/powershell/'>Powershell</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1749/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1749/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1749/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1749/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1749/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1749/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1749/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1749/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1749/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1749/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1749/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1749/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1749/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1749/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1749&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/07/27/a-tail-command-in-powershell/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>
	</item>
		<item>
		<title>More on regular expressions&#8211;(another reason why PowerShell beats VBscript)</title>
		<link>http://jamesone111.wordpress.com/2011/07/20/more-on-regular-expressionsanother-reason-why-powershell-beats-vbscript/</link>
		<comments>http://jamesone111.wordpress.com/2011/07/20/more-on-regular-expressionsanother-reason-why-powershell-beats-vbscript/#comments</comments>
		<pubDate>Wed, 20 Jul 2011 20:26:12 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Powershell]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/2011/07/20/more-on-regular-expressionsanother-reason-why-powershell-beats-vbscript/</guid>
		<description><![CDATA[For the last few weeks I’ve been settling into a new job in a small company which writes software; and that has meant getting used to some new tools. One of these is an issue tracking system named JIRA. This post isn’t about JIRA, except to say it generates a lot of e-mails – what [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1747&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>For the last few weeks I’ve been settling into a new job in a small company which writes software; and that has meant getting used to some new tools. One of these is an issue tracking system named <a href="http://www.atlassian.com/software/jira/">JIRA</a>. This post <u>isn’t about JIRA,</u> except to say it generates a lot of e-mails – what this post <u>is</u> about is parsing standardized blocks of text and JIRA’s subject lines provide a good example.&nbsp; If we create an ‘issue’ to look at how some data gets processed we might end up with pile of mails with subject lines like this.</p>
<p><code>
<p>[JIRA] Created: (Foo-164) Test Run – Data type # 2<br />[JIRA] Commented: (Foo-164) Test Run – Data type # 2<br />[JIRA] Updated: (Foo-164) Test Run – Data type # 2<br />[JIRA] Assigned: (Foo-164) Test Run – Data type # 2<br />[JIRA] Resolved: (Foo-164) Test Run – Data type # 2<br />[JIRA] Closed: (Foo-164) Test Run – Data type # 2</p>
<p></code>
<p>JIRA accounts for more than half of my messages, so I set up an Outlook rule to move them to their own folder. The format of the message is standardized. </p>
<p>“[JIRA]” <em>Event type </em>“(“ <em>project-ID “-” counter “)”</em>&nbsp;<em>issue-description</em></p>
<p>So it is pretty east to have a rule which looks for “[JIRA]” and moves messages to a new folder, but the format doesn’t help me sort and group messages – Outlook and Exchange can’t tell that the 6 messages above should be a single conversation. Sorting by date muddles all the issues and doesn’t group by project (“Foo” in my example). Sorting by subject groups all the <em>created</em> together, all the <em>closed</em> together and so on which is no better.&nbsp; So I came up with the idea of rewriting the subject line – which naturally I did from PowerShell to begin with: First I had to get the JIRA folder in my inbox. The method for this hasn’t changed since the first version of Outlook, even though the languages come and go. </p>
<p><code><span style="color:#ff4500;">$ns</span> <span style="color:#a9a9a9;">=</span> <span style="color:#000000;">(</span><span style="color:#0000ff;">New-Object</span> <span style="color:#000080;">-ComObject</span> <span style="color:#8a2be2;">outlook.application</span><span style="color:#000000;">)</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">getNameSpace</span><span style="color:#000000;">(</span><span style="color:#8b0000;">"MAPI"</span><span style="color:#000000;">)</span> <br /></code><code><span style="color:#ff4500;">$ExchStore</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$ns</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">stores</span> <span style="color:#a9a9a9;">|</span> <span style="color:#0000ff;">where-object</span> <span style="color:#000000;">{</span><span style="color:#ff4500;">$_</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">ExchangeStoreType</span> <span style="color:#a9a9a9;">-eq</span> <span style="color:#800080;">0</span><span style="color:#000000;">}</span> <span style="color:#a9a9a9;"><br /><code><span style="color:#ff4500;">$jiraFolder</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$ExchStore</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">folders<span style="color:#a9a9a9;">.</span>item(<span style="color:#8b0000;">'Inbox')<span style="color:#a9a9a9;">.</span><span style="color:#000000;">folders<span style="color:#a9a9a9;">.</span>item(<span style="color:#8b0000;">'JIRA')</span></span></span></span></code></span></code></p>
<p>The next bit does the work. I wrote it as ONE line of PowerShell but I’ve spaced it out here for easy reading </p>
<p><code><span style="color:#00008b;">foreach</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$item</span> <span style="color:#00008b;">in</span> <span style="color:#ff4500;">$jiraFolder</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Items</span><span style="color:#000000;">)</span> <span style="color:#000000;">{<br />&nbsp;&nbsp;&nbsp; </span></code><code><span style="color:#ff4500;">$item</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Subject</span> <span style="color:#a9a9a9;">=</span> <span style="color:#ff4500;">$item</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Subject</span> <span style="color:#a9a9a9;">-replace</span> <span style="color:#8b0000;">"^\[JIRA\](.*?)\((\w*-\d*)\)"</span><span style="color:#a9a9a9;">,</span><span style="color:#8b0000;">'$2 $1'<br /></span><span style="color:#ff4500;">&nbsp;&nbsp;&nbsp; $item</span><span style="color:#a9a9a9;">.</span><span style="color:#000000;">Save</span><span style="color:#000000;">(</span><span style="color:#000000;">)</span> <span style="color:#000000;">}</span></code> </p>
<p>The replace operation needs what a friend of mine calls a &#8220;<a href="http://en.wikipedia.org/wiki/Paddington_Bear">Paddington hard stare</a>&#8221; to understand it.&nbsp; </p>
<ul>
<li>“Look for the start of a line followed by &#8220;[JIRA]&#8221; ” is coded as&nbsp;&nbsp; <code><span style="color:#8b0000;"><strong><u>^\[JIRA\]</u></strong></span>&nbsp;<font color="#000000">&nbsp;</font></code><font color="#000000"> <br />The&nbsp; [] characters have special meaning in a regex so need to be escaped with a \ sign. </font></li>
<li><font color="#000000">“Any sequence of characters followed by &#8220;(&#8221; ” is coded <code><u><strong>.*\(</strong></u></code>&nbsp; <br />Like their square cousins, the () characters also have special meaning – which I’ll come to – and so they, too, need to be escaped with a \sign . </font></li>
<li><font color="#000000">Regular expressions are naturally “greedy” so if my subject line had been <br /></font><font color="#000000"><em>“[JIRA] Closed: (Foo-164) Test Run ( Data type # 2) <br /></em>The term <code><u><strong>.*\(</strong></u></code> would match all the way up to the second ( character. <br />Putting a ? symbol after the * tells it to to match using the shortest sequence of characters it can, so using&nbsp; <code><u><strong>.*?\(</strong></u></code>&nbsp; reduces the </font><span style="color:#8b0000;"><font color="#000000"><font color="#000000">match to </font><font color="#000000"><em>“ Closed: (”</em></font></font></span></li>
<li><span style="color:#8b0000;"><font color="#000000"><font color="#000000">Wrapping part of the expression in () saves it for later , so</font> <code><span style="color:#8b0000;"><u><strong>(.*?)\(</strong></u>&nbsp;</code></font><font color="#000000">will capture “<em>Closed:</em>” in this example </font></span></span></li>
<li><span style="color:#8b0000;"><span style="color:#8b0000;"></span></span><span style="color:#8b0000;"><font color="#000000"><code><strong><u>\w*-\d*\)</u> </strong></code>means any number of “word” characters , a &#8220;-&#8221; character, any number of “digit” characters and a &#8220;)&#8221;&nbsp; &#8211; which in my example will match&nbsp; on <em>“ Foo-164 )” </em></font></span></li>
<li><span style="color:#8b0000;"><font color="#000000">I can capture “Foo-164” by <span style="color:#8b0000;"><font color="#000000">inserting () </font></span>giving</font><font color="#000000"> <span style="color:#8b0000;"><code><strong><u>(\w*-\d*)\)</u> </strong></code></span></li>
</ul>
<p></font></span>
<p><span style="color:#8b0000;"><font color="#000000">Putting the pieces together I get </font></span><font color="#000000"><code><span style="color:#8b0000;"><strong><u>^\[JIRA\](<code><strong>.*?)\((<strong><u>\w*-\d*)\)</u></strong></strong></code></u></strong></code></font> </span><span style="color:#8b0000;"><font color="#000000">which matches on </font></span><span style="color:#8b0000;"><span style="color:#8b0000;"><font color="#000000"><em>“[JIRA] Closed: (Foo-164)” </em></font></span></span><span style="color:#8b0000;"><span style="color:#8b0000;"><font color="#000000"> and makes <em>“ Closed: ”</em> and <em>“Foo-164”; </em>available in the replacement text as $1 and $2 (note that PowerShell will process these as variables if the replacement text is wrapped in double quotes, so to ensure they reach regular expression parser <strong>single quotes </strong>are needed).&nbsp; So the –replace operation replaces <em>“[JIRA] Closed: (Foo-164)” </em>with<em> “FOO-164&nbsp; Closed.”</em> which is much better for sorting. <br />In practice I developed this a bit further by putting information into the message’s <em>userProperties</em>&nbsp; but my initial prototype shows the idea. </font></span></span></p>
<p>I ran this against the messages I had already received and it worked very nicely. But it would only work as an on-going solution <strong><u>if </u></strong>I was happy to run my PowerShell script for every new mail. I’m not. So I need something that Outlook can run automatically – Macros (Functions written in Outlook’s VBA environment) can be invoked by telling the rule to <em>Run a Script. </em>I found that the <em>Move-to-folder</em> rule-operation needs to be moved into the script (if the rules engine moves the message, the script doesn’t work).&nbsp; The line of PowerShell that was in the body of the <code>ForEach</code> loop in my example&nbsp; turns into this: </p>
<p><code>
<p>strSubject = objItem.Subject&nbsp;&nbsp; <br />If Left(strSubject, 6) = "[JIRA]" Then<br />&nbsp;&nbsp;&nbsp; openParen = InStr(strSubject, "(")<br />&nbsp;&nbsp;&nbsp; closeParen = InStr(openParen, strSubject, ")")<br />&nbsp;&nbsp;&nbsp; StrJIRASubject = Mid(strSubject, (closeParen + 2))<br />&nbsp;&nbsp;&nbsp; strJIRAAction = Mid(strSubject, 8, (openParen - 9))<br />&nbsp;&nbsp;&nbsp; strJIRAID = Mid(strSubject, (openParen + 1), (closeParen - openParen - 1))<br />&nbsp;&nbsp;&nbsp; objItem.Subject = strJIRAID + " " + strJIRAAction + " " + StrJIRASubject<br />&nbsp;&nbsp;&nbsp; objItem.Save<br />End If</p>
<p></code>
<p>You can see that here I have to check that line begins with [JIRA]: using –replace in&nbsp; PowerShell makes no changes if the match isn’t found, so doesn’t need to check – but VB script might scramble a non-JIRA subject line. <br />Then the script finds the positions of the Parentheses.<br />Then it has to isolate the pieces of text after the closing one, before the opening one but after &#8220;[JIRA] &#8221; and between the two. <br />Then it assembles these parts to make the new subject line and saves the message.</p>
<p><strong>I know people find&nbsp; regular expressions tough to follow</strong> but I’d say it was pretty hard to tell what is going on in the script, For example, take the line <br /><code>strJIRAAction = Mid(strSubject, 8, (openParen - 9))</code><br />Why select from character 8 for openParen –9 characters ?&nbsp;&nbsp; </p>
<p>[Answer: “[JIRA]” is 6 characters, character number 7 is a space so the word “Closed:” begins at&nbsp; character 8.&nbsp; From there up to the &#8220;(&#8221; is&nbsp; openParen – 8 characters , we want to stop one before that so we read openParen –9 characters and store “closed: ”&nbsp; in strJIRAAction] .<br /><strong>It takes time to work this out</strong>.&nbsp; If you know a little of the language of regex it takes less time to see that <font color="#000000"><code><span style="color:#8b0000;"><strong><u>^\[JIRA\](<code><strong>.*?)\( </strong></code></u></strong></span></code></font>will put “closed: ” into $1 </p>
<p>But there’s more.&nbsp; I alluded to the need to check for [JIRA] at the start of the subject line in VB script.&nbsp; The –Replace operator in PowerShell “Fails safe” Suppose a future version of [JIRA] changes from <em>“[JIRA] Closed: (Foo-164)” </em>to <em>“[JIRA] (Foo-164): Closed” , </em>the regular expression no longer matches, so nothing is changed. The VB script continues to run and … well you can try to work out what my Macro will do. The iterative development we tend to do in PowerShell lets you enter<br /><code>"[JIRA] Closed: (Foo-164) Test (type 2)" -match "^\[JIRA\].*\((.*)\)" ; $matches</code> <br />as a command line and see and fix the problem.&nbsp; Something you just can’t do so well with VBscript. </p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/powershell/'>Powershell</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1747/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1747/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1747/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1747/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1747/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1747/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1747/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1747/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1747/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1747/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1747/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1747/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1747/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1747/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1747&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/07/20/more-on-regular-expressionsanother-reason-why-powershell-beats-vbscript/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>
	</item>
		<item>
		<title>Ten tips for better PowerShell functions</title>
		<link>http://jamesone111.wordpress.com/2011/04/10/ten-tips-for-better-powershell-functions/</link>
		<comments>http://jamesone111.wordpress.com/2011/04/10/ten-tips-for-better-powershell-functions/#comments</comments>
		<pubDate>Sun, 10 Apr 2011 23:02:55 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/?p=1742</guid>
		<description><![CDATA[Explaining PowerShell often involves telling people it is both an interactive shell &#8211; a replacement for the venerable CMD.EXE &#8211; and a scripting language used for single task scripts and libraries of re-useable functions. There are some good practices which are common to both kinds of writing&#160; – including comments, being explicit with parameters, using [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1742&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Explaining PowerShell often involves telling people it is both an interactive shell &#8211; a replacement for the venerable CMD.EXE &#8211; and a scripting language used for single task scripts and libraries of re-useable functions. There are some good practices which are common to both kinds of writing&nbsp; – including comments, being explicit with parameters, using full names instead of aliases and so-on but having written hundreds of “script cmdlets” I have developed some views on what makes a good function which I wanted to share…</p>
<p><strong>1. Name your function properly</strong><br />It’s not actually compulsory to use <em>Verb-SingularNoun</em> names with the standard verbs listed by <code>Get-Verb</code>. “Helpers” which you might pop in a profile can be better with a short name. But if your function ends up in a module <code>Import-module</code> grumbles when it sees non-standard verbs. Getting <strong>the right name can clarify your thinking</strong> about what a command should or should not do. I cite <code>IPConfig.exe</code> as an example of a command line tool which didn’t know when to stop – what it does changes dramatically with different switches.&nbsp; PowerShell tends towards multiple smaller functions whose <u>names tell you what they will do</u> &#8211; which is a Good Thing </p>
<p><strong>2. Use standard, consistent and user-friendly parameters.<br /></strong>(a) PowerShell Cmdlets give you <code>–whatIf</code> and <code>–Confirm</code> switches; before you do something irreversible -&nbsp; you can get these in your own functions Put this line of code before any others in the function<br /><code>[CmdletBinding(SupportsShouldProcess=$True)]</code><br />and then where you do something which is hard to undo&nbsp;&nbsp; <br /><code>If ($psCmdlet.shouldProcess("Target" , "Action")) { <br />&nbsp;&nbsp;&nbsp; dangerous actions<br />}<br /></code>(b) Look at the names PowerShell uses: “path”, not “filename” , “ComputerName” not “Host”, “Force” “NoClobber” and so on – copy what has been done before unless you have a good reason to do something different; I don’t use “ComputerName” when working with Virtual Machines because it is not clear if it means a Virtual Machine or the Physical Machine which hosts them. <br />(c)If you are torn between two names : remember that “Computer” is a valid shortening of “ComputerName” and for names which are shortenings of an alternative you can define aliases, like this:<br /><code>[Alias("Where","Include")]$Filter<br /></code><strong>TIP 1.</strong>You can discover all the parameter names used in by cmdlets, and how popular they are like this <br /><code>get-command -c cmdlet | get-help -full| foreach {$_.parameters.parameter} |<br />&nbsp;&nbsp; forEach{$_.name} | group -NoElement | sort count</code><strong><br />Tip2</strong> If you think “Filter” is the right name to re-use you can see how other cmdlets use it like this:<code><br />Get-Command -C cmdlet | where { $_.definition -match "filter"} | get-help&nbsp; -Par "filter"&nbsp; </code></p>
<p><strong>3.</strong> <strong>Support</strong> <strong>Piping into your functions. <br /></strong>V2 of PowerShell greatly simplified Piping. The more you use PowerShell the stronger sense you get that the output of one command <em>should</em> become the input for another. If you are writing functions, <strong>aim for the ability to pipe into them and pipe their output into other things.&nbsp; </strong>Piped input becomes a <em>parameter</em>, all you need to do is </p>
<ul>
<li>Make sure the parts of the function which run for each piped object are in a<br /><code>process {}</code> block
<li>Prefix the parameter declaration with <code>[parameter(ValueFromPipeline=$true)]. </code>
<li><code></code>If you want a <em>property</em> of a piped object instead of the whole object, use <code>ValueFromPipelineByPropertyName </code>
<li><code></code>If different types of objects get piped, and they use different property names for what you want, give your parameter aliases, and it will look for the “true” name if it doesn’t find it try each alias in turn. </li>
</ul>
<p>If you find code that looks like this<br /><code><em>something</em> | foreach {<em>myFunction</em> $_ } </code><br />It is a sign that you probably need to look at piping. </p>
<p><strong>4. </strong><strong>Be flexible about arrays and types of parameters<br /></strong>Piping is one way to feed many objects into one command. In addition, many built-in cmdlets and operators will accept arrays as parameters just as happily as they would accept a single object; <a href="http://jamesone111.wordpress.com/2011/03/25/powershell-parameters-revisited/">previously</a> I gave the example&nbsp; of <code>Get-WmiObject </code>whose <code>–computername </code>parameter can specify a list of machines – it makes for simpler code. <br />It is easier to use the functions which <strong>catch being passed arrays and process them sensibly </strong>(and see <a href="http://jamesone111.wordpress.com/2011/03/25/powershell-parameters-revisited/">that previous post</a> for why simply putting <code>[String]</code> or <code>[FileInfo]</code> in front of a parameter doesn’t work).&nbsp; Actually I see it as good manners – “I handle the loop so you don’t have to do it at the command line”<br />Accepting arrays is one case of not being over-prescriptive about types: but it isn’t the only one. If I write something which deals with, say, a Virtual Machine, I ensure that VM <strong>names are just as valid as objects</strong> which represent VMs. For functions which work with files, it has to be just as acceptable to pass <code>System.IO.FileInfo</code> and <code>System.Management.Automation.PathInfo</code>, objects or strings containing the path (unique or <strong>wild card, relative path or absolute</strong>).&nbsp; <br /><strong>TIP:&nbsp; </strong><code>resolve-path</code> will accept any of these and convert them into objects with fully-qualified paths.<br />It seems rude to make the user use <code>Get-<em>whatever</em></code> to fetch the object if I can do it for them.</p>
<p><strong>5. Support ScriptBlock parameters.</strong> <br />If one parameter can be calculated from another it is good to let the user say <em>how</em> to do the calculation.&nbsp; Consider this example with <code>Rename-Object</code>. I have photos named IMG_4000.JPG, IMG_4001.JPG , IMG_4002.JPG, up to IMG_4500.JPG. They were taken underwater, so I want them to be named DIVE4000.JPG etc. I can use:<br /><code>dir IMG_*.JPG | rename-object –newname {$_.name –replace "IMG_","DIVE"}</code> <br />In English “Get the files named IMG_*.JPG and rename them. The new name for each one is the result of replacing IMG_ with DIVE in that one’s current name.” Again you can write a loop to do it but a script block saves you the trouble. </p>
<ul>
<li>The main candidates for this are functions where one parameter is piped and a second parameter is connected to a property of the Piped one.
<li>When you are dealing with multiple items arriving from the pipeline, be careful what variables you set in the process{} block of the function: you can introduce some great bugs by overwriting non-piped parameters. For example if you had to implement rename-object, it would be valid to handle a string that had been piped in as the –path parameter by converting it into a FileInfo object – doing so has no effect on the next object to come down the pipe; but if you convert a script block which is passed as -NewName to a String, when the next object arrives it will get that string – I’ve had great fun with the bugs which result from this
<li>All you need to do to provide this functionality is <br /><code>If ($newname –is [ScriptBlock]) { $TheNewName = $newname.invoke() }<br />else&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { $TheNewName = $newname} </code></li>
</ul>
<p><strong>6. Don’t make input mandatory if you can set a sensible default. <br /></strong>Perhaps obvious, but… If I write a function named “Get-VM” which finds virtual machines with a given name, what should I do if the the user doesn’t give me a VM name ? Return nothing ? Throw an error ? Or assume they want all possible VMs ? <br />What would <em>you</em> mean if <em>you </em>typed Get-VM on its own ? </p>
<p><strong>7. Don’t require the user to know too much underlying syntax. <br /></strong>Many of my functions query WMI; WMI uses SQL syntax; SQL Syntax uses “%” as a wildcard, not “*”.&nbsp; Logical conclusion: if a user wants to specify a wildcarded filter to my functions they should learn to use % instead of *.&nbsp; That just seems wrong to me: so my code replaces any instance of * with %.&nbsp; If the user is specifying filtering or search terms a few lines to change the from things they will instinctively do, or wish they could do, to what is required for SQL,&nbsp; LDAP or any other syntax can make a huge difference in usability. </p>
<p><strong>8. Provide information with Write-Verbose , Write-debug and Write-warning<br /></strong>When you are trying to debug the natural reaction is to put in <code>Write-Host</code> commands, fix the problem and take them out again.&nbsp; Instead of doing that change <code>$DebugPreference</code> and/or <code>$VerbosePreference</code> and use <code>write-debug</code> / <code>write-verbose</code> to output information. You can leave them in and stop the output by changing the preference variables back. If your function already has <br /><code>[CmdletBinding(SupportsShouldProcess=$True)]<br /></code>at the start then you get <code>–debug</code> and <code>–verbose</code> switches for free. <br /><code>Write-Error</code> is ugly and if you are able to continue, it’s often better to use <code>Write-warning</code>. <br />And learn to use <code>write-progress</code> when you expect something to spend a long time between screen updates.</p>
<p><strong>9. Remember: your output is someone else’s input.<br /></strong>(a) Point 8&nbsp; Didn’t talk about using <code>Write-Host</code> – only use it to display something you want to prevent going into something else. <br />(b) <strong>Avoid formatting output</strong> in the function, try to <strong>output objects which can be consumed</strong> by something else.&nbsp; If you <em>must</em> format turn it on or off with a –formatted or -raw switch.<br />(c) Think about the <em>properties</em> of the objects you emit. Many commands will understand that something is a file if it has a <code>.Path</code> property, so add one to the objects coming out of your function and they can be piped into <code>copy</code>, <code>invoke-item</code>, <code>resolve-path</code> and so on. Usually that is good – and if it might be dangerous look at what you can do to change it.&nbsp; Another example: when I get objects that represent components of a virtual machine their properties don’t include the VM name. So I go to a little extra trouble to add it. <br /><code>Add-Member</code> can add properties or aliases for properties to an object for example<br /><code>$obj | Add-member -MemberType AliasProperty –Name "Height"-Value “VerticalSize”</code></p>
<p>10<strong> Provide help <br /></strong>In-line help is easy – it is just a carefully comment before any of the code in your function. It isn’t just there for some far when you share the function with the wider world. It’s for you when you are trying to figure out what you did months previously – and Murphy’s law says you’ll be trying to do it at 3AM when everything else is against you.<br />Describe what the Parameters expect and what they can and can’t accept.&nbsp; <br />Give examples (plural) to show different ways that the function can be called. And when you change the function in the future, check the examples still work. </p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/uncategorized/'>Uncategorized</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1742/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1742/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1742/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1742/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1742/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1742/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1742/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1742/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1742/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1742/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1742/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1742/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1742/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1742/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1742&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/04/10/ten-tips-for-better-powershell-functions/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>
	</item>
		<item>
		<title>Pattern recognition&#8211;the human and PowerShell kinds</title>
		<link>http://jamesone111.wordpress.com/2011/04/09/pattern-recognitionthe-human-and-powershell-kinds/</link>
		<comments>http://jamesone111.wordpress.com/2011/04/09/pattern-recognitionthe-human-and-powershell-kinds/#comments</comments>
		<pubDate>Sat, 09 Apr 2011 20:40:50 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/?p=1740</guid>
		<description><![CDATA[Recently BBC’s Top Gear has been promoting the idea that a particular type of obnoxious drivers have been replacing the BMWs that they traditionally bought with Audis. Chatting to a friend who is a long term Audi customer, and whose household features ‘his’ and ‘hers’ Audis we came to the conclusion that once you think [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1740&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Recently BBC’s Top Gear has been promoting the idea that a particular type of obnoxious drivers have been replacing the BMWs that they traditionally bought with Audis. Chatting to a friend who is a long term Audi customer, and whose household features ‘his’ and ‘hers’ Audis we came to the conclusion that once you think there is a pattern, you recognise it and the your awareness increases &#8211; even if in reality it is no more prevalent. I think the same thing happens in IT in general and scripting in particular – it has happened to me recently&#8230; when&nbsp; my understanding of <strong>regular expressions</strong> in PowerShell took a big step forward, and now I’m finding all manner of places where it helps. </p>
<p>I use a handful of basic regular expressions&nbsp; for things like removing a trailing \ character from the end of a string with something like: <br /><code>$Path = $Path –replace "\\$" , ""<br /></code>Many people use –replace to swap text without realising it handles regular expressions – in this case&nbsp; “\” is the escape character in regular expression, so to match “\” itself it has to escaped as “\\” . The $ character means “<em>end-of-line</em>” so this fragment just says ‘Replace “\” at the end of $Path – if you find one &#8211; with nothing, and store the result back in $Path.&nbsp; PowerShell’s <code>–Split</code> operator also uses regular expressions. This can be a trap – if you try to split using&nbsp; “.” it has means “any character” any you get a result you didn’t expect: <br /><code>This.that" –split "." </code>returns 10 empty strings – (the –split operator discards the delimiter) ; to match a “.” it must&nbsp; be escaped as “\.” . But it’s also a benefit if you want to split sentences apart you can make&nbsp; “.” and any spaces round it the delimiter– which saves the need to trim afterwards. The –<code>Match</code> operator uses regular expressions too&nbsp; – I&nbsp; worry when I see it used in examples for new users who may use something which parses unexpectedly as a regular expression .</p>
<p>I thought that I knew regular expressions – until thanks to <a href="http://blogs.technet.com/b/heyscriptingguy/archive/2011/03/03/use-powershell-regular-expressions-to-format-numbers.aspx">an article by Tome Tanasovski</a>, I found I had missed a big bit of the picture, which meant my understanding was wrong.&nbsp; I thought that a <em>match</em> meant the equivalent of running a highlighter pen over part of the text and –replace means “take something out and put something else back” – both are usually true but not always. Tome also did a presentation for the PowerShell user group – there’s a link to the recording on <a href="http://richardspowershellblog.wordpress.com/2011/03/23/regular-expression-recording/">Richard’s blog</a> – I’d recommend watching it and pausing every so often to try things out. <br />Tome showed<em> look-aheads</em> and <em>look-behinds</em>. These say “It’s a Match if it is followed by something”, or “preceded by something” (or not).&nbsp; This adds a whole new dimension… </p>
<p>A couple of days later I hit a snag with PowerShell’s <code>Split-Path</code> cmdlet. If the path is on a remote machine it might uses a drive letter which doesn’t exist on the local machine – and in that situation <code>Split-Path</code> throws an error. But I can use the <code>–Split</code> operator with a regular expression. I want to say “Find a \ followed by some characters that <em>aren’t</em> \ and the end of the string”. Lets test this:<br /><code>PS C:\Users\James\Documents\windowsPowershell&gt; $pwd -split "\\[^\\]+$"<br />C:\Users\James\Documents</p>
<p></code>
<p>As in my first example&nbsp; ‘\\’ is an escaped ‘\’ character, and ‘$’ means “end of line” , ‘[^\\]’ says “Anything which <em>not </em>the ‘<em>\’ </em>character”&nbsp; and ‘+’ means “at least once” So this translates as “Look for a ‘\’ followed my at least 1 non-‘\’ followed by end of line”. <u><strong>It’s mostly right but it doesn’t work</strong></u> (yet). <br />I copied my command prompt so you can see that ‘WindowsPowerShell’ is part of the my working directory – but that bit got lost; or to be more precise it was matched in the expression, so –split <u>returned the text on either side of it</u>. <br />I want to say “Find <u>ONLY</u> a ‘\’ . The one you want is followed by some characters that <em>aren’t</em> ‘\’ and the end of the string but they don’t form part of the delimiter.”&nbsp; The syntax for <em>Is followed by</em> is “(?=&nbsp;&nbsp; )” so I can wrap that around the [^\\]+$ part&nbsp; and test that: <br /><code>PS C:\Users\James\Documents\windowsPowershell&gt; $pwd -split "\\(?=[^\\]+?$)"<br />C:\Users\James\Documents<br />windowsPowershell</code></p>
<p>Regular-Expressions can turn into a <a href="http://en.wikipedia.org/wiki/APL_(programming_language)">write-only language</a> – easy to build up but pretty hard to pull apart.&nbsp; At risk of making things worse, not everyone knows that PowerShell has a “multiple = operator”; if you write <code>$a , $b&nbsp; = 1,2&nbsp; </code>it will assign 1 to $a and 2 to $b. Since the output of the split operation is 2 items we can try this <br /><code>PS C:\Users\James\Documents\windowsPowershell&gt; $Parent,$leaf = $pwd -split "\\(?=[^\\]+?$)"<br />PS C:\Users\James\Documents\windowsPowershell&gt; $Parent<br />C:\Users\James\Documents<br />PS C:\Users\James\Documents\windowsPowershell&gt; $leaf<br />windowsPowershell<br /></code></p>
<p>The “cost” of using regular expressions is that the term used to do the split is something akin to a magical incantation. The benefit is code is a lot more streamlined than using the string object’s&nbsp; .LastInstanceOf(), .Substring() and .length() methods and some arithmetic to get to the same result. I’d contend that even allowing for the “incantation” the regex way makes it easier to see that $pwd is being split into 2 parts. <br /><strong>Good stuff so far</strong>, but Tome had another trick:&nbsp; <strong>the match that selects nothing and the replace that removes nothing</strong>.&nbsp; That made me stop and redefine my understanding.&nbsp; Here’s the use case:</p>
<p>Ages ago I wrote about using PowerShell to query the Windows [Vista] Destkop Index – it works just as well with Windows 7.&nbsp; The <a href="http://msdn.microsoft.com/en-us/library/dd561977(v=VS.85).aspx">a zillion or so field names</a> used in these queries have names like&nbsp; “System.Title”, “System.Photo.Orientation” and “System.Image.Dimensions” – I’d type the bare field name like “title” by mistake or waste time discovering whether “HorizontalSize” belonged to System.Photo or System.Image.&nbsp; <br />It would be better to enable my <em>Get-IndexedFile</em> function to put in the the right prefix: but could it be done reasonably efficiently and elegantly? <br />Here lookarounds come into their own. They let me write “If you can find a spot which is immediately after a space, and immediately before the word ‘Dimensions’ OR the word ‘HorizontalSize’ OR…” and so on for all the Image Fields “AND that word is followed by any spaces and a ‘=’ sign&nbsp; THEN put ‘System.image.’ at the spot you found”.&nbsp; With just the first two fieldnames the operation looks like this<br /><code>-replace "(?&lt;=\s) (?=(Dimensions|HorizontalSize)\s*=)" , "system.image."<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ^<br /></code>I have put an extra space in for the spot that will be matched – the ^ is pointing this out, it isn’t part of the code. <br />“(?&lt;=&nbsp; )” is the wrapper for the “look <em>behind</em>” operation&nbsp; (replacing the ‘=’ with ‘!’ negates the expression) so “(?&lt;=\s)”&nbsp; says “behind this spot you find a space” and the second half is a “look <em>ahead</em>” which says “in front of this spot you find ‘Dimensions’ or ‘HorizontalSize’ then zero or more spaces (‘\s*’) followed by ‘=’ ”. A match with an expression like this is like an I-beam cursor between characters – rather than highlighting some: so the –replace operator has nothing to remove but it still inserts ‘system.image’ at that point. So lets put that to the test. </p>
<p><code>PS&gt; "horizontalsize = 1024"&nbsp; -replace "(?&lt;=\s)(?=(Dimensions|HorizontalSize)\s*=)",<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "system.image."<br />system.image.horizontalsize = 1024</code></p>
<p>It works !&nbsp; This whole exercise of writing a Get-IndexedFilesfunction – which I will share in due course -&nbsp; ended up as worked example in using regex to support good function design. I’ve got another post in draft at the moment about my ideas on good function design, so I’ll post that and then come back to looking at all the different ways I made use of regular expressions in this one function. </p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/uncategorized/'>Uncategorized</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1740/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1740/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1740/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1740/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1740/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1740/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1740/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1740/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1740/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1740/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1740/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1740/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1740/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1740/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1740&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/04/09/pattern-recognitionthe-human-and-powershell-kinds/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>
	</item>
		<item>
		<title>F1: The hidden effects of moving wings</title>
		<link>http://jamesone111.wordpress.com/2011/03/26/f1-the-hidden-effects-of-moving-wings/</link>
		<comments>http://jamesone111.wordpress.com/2011/03/26/f1-the-hidden-effects-of-moving-wings/#comments</comments>
		<pubDate>Sat, 26 Mar 2011 22:25:38 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/2011/03/26/f1-the-hidden-effects-of-moving-wings/</guid>
		<description><![CDATA[There seem to be divided opinions about the effect of the “Drag reduction system” introduced in F1 this season. The rules are that Drivers can operate device to lower the effective part of the rear wing, cutting both lift and drag. The wing returns to its original position when the driver applies the brakes. In [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1739&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>There seem to be divided opinions about the effect of the “Drag reduction system” introduced in F1 this season. The rules are that</p>
<ul>
<li>Drivers can operate device to lower the effective part of the rear wing, cutting both lift and drag. The wing returns to its original position when the driver applies the brakes. </li>
<li>In wet conditions this will be disabled</li>
<li>In qualifying the drivers can use this at will</li>
<li>In the race it is armed remotely by a system in race control – if the car close enough to the one in front (the margin will be 1 second to begin with – this my change over the season) at a specific point the following driver can lower his wing for a specific section of the track – typically the longest straight. .</li>
</ul>
<p>“Push to pass” divides people: we had it in the days of turbo engines: in the 1980s we had qualifying engines which wouldn’t last a race distance; the boost button in a race gave a burst of similar power &#8211; for a sustained period it was a case of “The engines cannae’ take it”, nor could the tyres, and fuel would run&nbsp; out. We it had when KERS first appeared;&nbsp; “Kinetic Energy Recovery Systems” are currently a gimmick: energy stored, rate at which it is returned (Power) and time over which the return can take place are all constrained. F1 talks about being greener, removing the limits on KERS would be an obvious way and I’d have it feeding extra power in when the driver applied full throttle. Now we have it with wings. </p>
<p><strong>Predicted effect 1.</strong> <strong>Last use wins.</strong> IF it turns out to make passing easy then if two cars are evenly matched, drivers won’t want to be re-passed, so they will time their passing move to use the wing at the last moment</p>
<p><strong>Predicted effect 2.</strong> <strong>More tyre stops.</strong> There was always a decision to make: sacrifice position on-track by making a stop for fresh tyre – or hold out ? The harder it is to overtake the bigger the advantage of fresh rubber needs to be before stopping becomes the preferred option – because as Murray Walker always used to say “Catching is one thing, passing is quite another”.&nbsp; So picture the scene with a dozen or so laps to go the first two cars have been on hard tyres for a good few laps and the leader is being caught: thanks to DRS the 2nd place car gets past. The former leader’s his car is fractionally slower but on fresh soft tyres could go 2-3 seconds a lap quicker – enough to catch the 20-30 seconds a pit stop takes with a couple of laps to go. Most of the tyre advantage will have gone by the time he has caught up: previously it would have been easy for the new leader to defend for the last couple of laps. Now if the chasing car can get within DRS distance he should be able to make a last gasp pass.&nbsp; In the wet inspired changes of tyres win races – it didn’t really happen in the dry – until now. </p>
<p><strong>Predicted effect 3.</strong> <strong>The return of slipstreaming.</strong> The FIA banned slipstreaming… OK, not as such. Imposing an 18,000 Rev limit banned it. How so ?&nbsp; Without a limit on revs, in top gear, revs and speed increase until the acceleration force coming from the engine matches the retardation force from friction and aerodynamic drag.&nbsp; Reduce drag by slipstreaming and top speed and engine revs will increase. But what if gear ratios are optimised to get the best lap time with no slipstream (in qualifying) – hitting the maximum Revs as the driver hits the brake at the fastest point ? If revs are limited the car won’t go any faster with the aid of slipstream. </p>
<p>With the ability to use DRS in qualifying, the optimum is to hit 18,000 in low-drag trim at the fastest point. The teams can’t change gear ratios after qualifying and the race the cars will be in high-drag trim most of the time – so they won’t be reaching 18,000 revs and will have a margin for slipstreaming. </p>
<p><strong>Predicted effect 4. Race pace trumps grid place. Grid penalties become less effective.</strong> The advantage of starting ahead of a car which is faster than then yours / or disadvantage of starting behind a slower car varies with the difficulty in passing. Since the car can’t be reconfigured after qualifying, making overtaking easier might mean car set-up is tilted more towards race configuration than qualifying. It also means taking a penalty for a precautionary gearbox change (say) is smaller</p>
<p>Whether or not any of these things happen remains to be seen. Still: fun season in prospect.</p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/uncategorized/'>Uncategorized</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1739/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1739/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1739/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1739/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1739/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1739/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1739/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1739/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1739/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1739/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1739/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1739/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1739/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1739/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1739&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/03/26/f1-the-hidden-effects-of-moving-wings/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>
	</item>
		<item>
		<title>PowerShell parameters revisited.</title>
		<link>http://jamesone111.wordpress.com/2011/03/25/powershell-parameters-revisited/</link>
		<comments>http://jamesone111.wordpress.com/2011/03/25/powershell-parameters-revisited/#comments</comments>
		<pubDate>Fri, 25 Mar 2011 20:49:07 +0000</pubDate>
		<dc:creator>jamesone111</dc:creator>
				<category><![CDATA[Powershell]]></category>

		<guid isPermaLink="false">https://jamesone111.wordpress.com/2011/03/25/powershell-parameters-revisited/</guid>
		<description><![CDATA[A little while back, as a follow up to a talk I’d given, I wrote a post entitled why it is better not to use PowerShell Parameter validation. I repeated the talk recently and met up with Thomas who’d organized both.&#160; His initial instinct had been that my “best practice” of NOT declaring parameter types [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1738&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>A little while back, as a follow up to a talk I’d given, I wrote a post entitled <a href="https://jamesone111.wordpress.com/2011/01/11/why-it-is-better-not-to-use-powershell-parameter-validation/">why it is better not to use PowerShell Parameter validation</a>. I repeated the talk recently and met up with <a href="http://tfl09.blogspot.com/">Thomas</a> who’d organized both.&nbsp; His initial instinct had been that my “best practice” of NOT declaring parameter types was just wrong – it’s not a surprising view given what he has been exposed to…. </p>
<p>Over a quarter of a century ago, when I was studying computer science at University, one of the lecturers wrote the following quote from Dykstra on the board: “<em>It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration.”</em><br />I might be pushing a heavy stone up a steep hill here, trying to overcome the “mental mutilation” of <strong>too much “good programming”.</strong> But to see why “good programmers” can get the declaration of parameter types wrong in PowerShell, consider this example:<br /><code class="PowerShellColorizedScript"><span style="color:#00008b;">Function</span> <span style="color:#8a2be2;">Use-File</span> <span style="color:#000000;">{</span> <span style="color:#00008b;">Param</span> <span style="color:#000000;">(</span><span style="color:#008080;">[System.io.FileInfo]</span><span style="color:#ff4500;">$theFile</span> <span style="color:#000000;">)</span> <br />&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#0000ff;">Format-list</span> <span style="color:#000080;">-InputObject</span> <span style="color:#ff4500;">$thefile</span> <span style="color:#000080;">-Property</span> <span style="color:#8a2be2;">*</span> <br /><span style="color:#000000;">}</span> <br /></code></p>
<p><code class="PowerShellColorizedScript"><span style="color:#008080;">[string]</span><span style="color:#ff4500;">$f</span><span style="color:#a9a9a9;">=</span><span style="color:#8b0000;">".\Event.txt"</span> <br /><span style="color:#0000ff;">Use-File</span> <span style="color:#ff4500;">$f</span> </code></p>
<p>Simple stuff: I declare a function with one parameter &#8211; a <u>FileInfo</u> object – which outputs a list showing all the properties of that object. <br />Then I pass a <u>string</u> to the function – and it contains a relative path to a file held in the current folder. So … What comes out of the function ? </p>
<ol>
<li>An error, or.
<li>The properties for the file in the current folder , or
<li>Something else ?</li>
</ol>
<p>If you have a “good programming” background I’d expect you to say <strong>“An error”.</strong> Experience tells you passing a type other than the specified one does that. <strong><u>Not here</u></strong>. <br />In a shell you don’t want to worry about the type of object which comes out of one command or goes into the next, so PowerShell smooths out differences between types. Ask it to evaluate &#8220;Fire &#8221; + 1 and it does an <em>implicit conversion</em> – usually called a type <em>cast</em> &#8211; of the second argument to the type of the first and returns “Fire 1”. <br />(1 + “Fire” fails because when it applies the rule of converting to match the first, “fire” can’t be turned into a number). <br />After spending a while doing only PowerShell, a compiled language like C# seems to need a huge number of “cast to String”, “Isn’t null”, “Isn’t empty”, “Is non-zero” operations, because it requires cast to string or Boolean types to be <em>explicit.&nbsp; </em>It’s not one is good and the other bad, the different environments impose different requirements. </p>
<p>In PowerShell putting [Type] is how you explicitly cast something to a different type. <strong>[FileInfo] does not say “Reject anything which isn’t a file” as it would in C#, <br />it says to PowerShell “<em>Convert</em> anything which isn’t a file…”. <br /></strong>So, what conversion does it attempt? The underlying FileInfo .net object has a <em>constructor </em>which accepts a string and returns a file, so PowerShell creates a new FileInfo object using the constructor and passing in the string.&nbsp; Unfortunately the constructor doesn’t handle the relative path, so the object which comes back&nbsp; represents a non-existent read-only file in the windows\system32 folder. Yes you did read correctly, it doesn’t exist and you can’t write to it.&nbsp; </p>
<p>I was taught to be <em>as clear as the tools allowed</em> about data types. It’s my contention that “good programmers” learn that it is <strong>dangerous to assume</strong> parameters will be an acceptable type; so when it is optional to specify types they will still do so out of habit. In PowerShell that leads to a <strong>more dangerous (and hidden) assumption- </strong>that what is passed will be the correct type or will fail if it can’t be cast correctly.&nbsp; But what if a casting operation yields a nonsense result as it does here? </p>
<p>“Good programmers” accept <strong>writing something for type changes as a necessary a safety mechanism; </strong>at a command line it’s unnecessary pedantry. But PowerShell is both command line AND programming environment; and when we program in PowerShell we want to do it <em>well</em>, don’t we ?&nbsp; <br />In <a href="https://jamesone111.wordpress.com/2011/01/11/why-it-is-better-not-to-use-powershell-parameter-validation/">that previous post</a> I argued functions should cope with be passed names (paths in the example) and resolve them to the desired object (a file).&nbsp; If a user expects to supply a file to your function by typing part of its name and hitting the [TAB] key then you have to write something <em>after the parameter declaration</em> (like a <code>resolve-path</code> statement) to cope with the change of type; it’s slightly different code to that which C# programmers need to write, but we don’t escape the task completely. </p>
<p>You might have thought ahead and asked “What would happen if I wrote”<br /><code><span style="color:#008080;"><span style="color:#00008b;">Param</span> <span style="color:#000000;">(</span>[String]</span><span style="color:#ff4500;">$theFile<span style="color:#000000;">)</span></span></code> instead ? If the function is passed a file won’t casting it to string give me the full path ? That WILL work, but here’s an example to show why you should not use <code><span style="color:#008080;">[String]</span></code>:</p>
<p><code><span style="color:#00008b;">Function</span> <span style="color:#8a2be2;">Use-word</span> <span style="color:#000000;">{</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; <span style="color:#00008b;">Param</span> <span style="color:#000000;">(</span><span style="color:#008080;">[string]</span><span style="color:#ff4500;">$theword</span> <span style="color:#000000;">)</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; <span style="color:#0000ff;">write-host</span> <span style="color:#8b0000;">"**$theWord**"</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /><span style="color:#000000;">}</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /><span style="color:#ff4500;">$w</span> <span style="color:#a9a9a9;">=</span> <span style="color:#8b0000;">"Hello"</span><span style="color:#a9a9a9;">,</span><span style="color:#8b0000;">"world"</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /><span style="color:#0000ff;">Use-word</span> <span style="color:#ff4500;">$w</span></code></p>
<p>This&nbsp; function takes a single string&nbsp; &#8211; and writes that string to the console: but I haven’t passed it a single string but an array containing&nbsp; “Hello” and “world”.&nbsp; I’ll pose the same question as before: what comes out ?</p>
<ol>
<li>An error.
<li>**Hello** (the first item in the array “wins”)
<li>**World** (the last item in the array “wins”)
<li>**Hello World**&nbsp;&nbsp;
<li>Something else.</li>
</ol>
<p>If your instincts said “An array of X into something which takes a single X won’t go so this should give an error” but you now doubt them, I’ve achieved something. <br />In fact, when PowerShell casts an array to a single string it converts the members to strings and concatenates them with spaces between each.<code>[string]("hello","world")</code> returns “Hello world”.&nbsp; With paths, two valid paths will become a string which is not a valid path. </p>
<p></strong>A lot of PowerShell cmdlets will accept arrays instead of a single parameter.&nbsp; Operators also work with arrays&nbsp; <code>"hello","world" -split "l"</code> gives the same result as<br /><code>"hello" -split "l" ; "world" -split "l".</code><br />For a cmdlet example, you can get the a list of QFEs (Hotfixes) installed on a computer with&nbsp; <code>Get-WmiObject -class win32_QuickFixEngineering</code><br />You can find the results on multiple machines (if they are set up for remote WMI) with<br /><code>Get-WmiObject -class win32_QuickFixEngineering –computer Server1,Server2,serverN<br /></code>because the <code>Get-WmiObject </code>cmdlet accepts an array in the <code>–computername </code>parameter. </p>
<p>Any function which takes a <code>–computername </code>parameter does not even need to look at it before passing to <code>Get-WmiObject </code>cmdlet.&nbsp; But this seems wrong or at least lazy: surely we should catch an error as soon as possible ? Here’s one last example to show what difference it makes: </p>
<p><code class="PowerShellColorizedScript"><span style="color:#00008b;">Function</span> <span style="color:#8a2be2;">Use-integer</span> <span style="color:#000000;">{<br /></span>&nbsp;&nbsp; <span style="color:#00008b;">Param</span> <span style="color:#000000;">(</span><span style="color:#ff4500;">$theNumber</span> <span style="color:#000000;">)</span> <br /><span style="color:#0000ff;">&nbsp; start-sleep</span> <span style="color:#ff4500;">$theNumber<br /></span><span style="color:#000000;">}</span> </code></p>
<p><code class="PowerShellColorizedScript"><span style="color:#ff4500;">$n</span> <span style="color:#a9a9a9;">=</span> <span style="color:#8b0000;">"hello"</span> <br /><span style="color:#0000ff;">Use-integer</span> <span style="color:#ff4500;">$n</span></code> </p>
<p>So here I <u>Don’t</u> validate that $number is actually a number, and I pass in “Hello”, and Start-Sleep will generate an error which looks like this</p>
<p><code><span style="color:#ff4500;">Start-Sleep : Cannot bind parameter 'Seconds'.<br />Cannot convert value "hello" to type "System.Int32". <br />Error: "Input string was not in a correct format."</p>
<p></span></code>
<p>If&nbsp; I DO validate that $number is a number, I get this</p>
<p><code><span style="color:#ff4500;">Use-integer : Cannot process argument transformation on parameter 'theNumber'.<br />Cannot convert value "hello" to type "System.Int32".<br />Error: "Input string was not in a correct format."</span></code></p>
<p>Early validation didn’t gain anything <u>in this case</u>. It <u>might</u> have saved me from using a lot of time/system resources before the error. If $ErrorActionPreference is set to “Continue”, which it is by default, my function <u>might</u> continue on to something stupid, and early validation would stop that.&nbsp; So it is <u>not</u> universally wrong to use [type] validate parameters, you just need to ask two questions: “Does what I am doing catch what I need to ?” and “Does what I am doing handle that in the best way”. <strong>Best way includes handling names and paths for objects, handling arrays and even (if you’re really bold) handling script block parameters. </strong>This post has gone quite long enough so I’ll talk about those in another post. </p>
<br />Filed under: <a href='http://jamesone111.wordpress.com/category/powershell/'>Powershell</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jamesone111.wordpress.com/1738/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jamesone111.wordpress.com/1738/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jamesone111.wordpress.com/1738/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jamesone111.wordpress.com/1738/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jamesone111.wordpress.com/1738/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jamesone111.wordpress.com/1738/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jamesone111.wordpress.com/1738/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jamesone111.wordpress.com/1738/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jamesone111.wordpress.com/1738/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jamesone111.wordpress.com/1738/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jamesone111.wordpress.com/1738/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jamesone111.wordpress.com/1738/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jamesone111.wordpress.com/1738/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jamesone111.wordpress.com/1738/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jamesone111.wordpress.com&amp;blog=15763423&amp;post=1738&amp;subd=jamesone111&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jamesone111.wordpress.com/2011/03/25/powershell-parameters-revisited/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/256a9fa9cbef2fc1e3230fb3797360b9?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jamesone111</media:title>
		</media:content>
	</item>
	</channel>
</rss>
