Posts Tagged ‘.Net’

Although there are a few “CSS Selector” libraries, most browsers haven’t even implemented CSS3 selectors, never mind frameworks like .Net or scripting languages like Javascript or PowerShell ;) so XPath remains the most powerful way to deal with finding specific data in an XML file, and by extension, XHTML and even HTML files (if you can convert them using something like SgmlReader) is to use XPath queries.

There are a lot of XPath tutorials around the web, so there’s no need for me to get into that very much, but I just wanted to write a brief note about using XPath with documents that have namespaces (particularly, from .Net). The problem is that in order to select nodes that have a namespace assigned, you must use a namespace prefix and a NamespaceManager. So even if it’s the default namespace, if there’s an xmlns=”...” on the document, you have to create and use a prefix.

The bottom line is this: if you have an XML document that looks like this:


<event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <system>
    <eventid>100</eventid>
    <version>2</version>
    <level>1</level>
    <task>4002</task>
    <opcode>34</opcode>
  </system>
  <eventdata>
    <data name="BootTsVersion">2</data>
    <data name="BootStartTime">2009-11-22T08:45:11.640400200Z</data>
    <data name="BootEndTime">2009-11-22T08:48:23.432178500Z</data>
    <data name="SystemBootInstance">18</data>
    <data name="UserBootInstance">15</data>
  </eventdata>
</event>
 

That bit at the top where it says: xmlns="http://schemas.microsoft.com/win/2004/08/events/event" is assigning a default namespace. Sometimes you’ll see something like this (eg: in RSS):


<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/">
   <channel>
      <item>
         <title>Buttons</title>
         <link />http://www.flickr.com/photos/jaykul/4114286262/
         <description>Quick cut-n-paste from a screenshot</description>
         <pubdate>Tue, 17 Nov 2009 20:46:31 -0800</pubdate>
         <guid ispermalink="false">tag:flickr.com,2004:/photo/4114286262</guid>
                        <media:content url="http://farm3.static.flickr.com/2552/4114286262_001e2f8905_o.png" type="image/jpeg" height="157" width="337">
                        <media:title>Buttons</media:title>
                        <media:description type="html">&lt;p&gt;Quick cut-n-paste from a screenshot into your mockup&lt;/p&gt;</media:description>
                        <media:thumbnail url="http://farm3.static.flickr.com/2552/4114286262_cba8aaf967_s.jpg" height="75" width="75">
                        <media:credit role="photographer">Jaykul</media:credit>
                        <media:category scheme="urn:flickr:tags">screenshot snagit</media:category>
      </media:thumbnail>
       </media:content>
</item>
</channel></rss>

This one assigns a specific prefix “media” to the namespace url “http://search.yahoo.com/mrss/” ...

Selecting nodes with namespaces

In either case, if you want to select a node that’s assigned to a namespace (which is ALL the nodes in the first example, but just the ones that start with media: in the second example) in .net, you have to specify the namespace in order to select those nodes with XPath. PowerShell 2.0 has a Select-Xml cmdlet which accepts -Namespaces as a parameter: you simply provide a hashtable of names to urls.

If you had loaded the first document above into $xml, you could select the BootStartTime and BootEndTime using an XPath query like this: //e:Data[Name = ‘BootStartTime’ or Name = 'BootEndTime'] but we have to DEFINE that “e” namespace. To do so using Select-Xml you just pass it into the command


$xpath = @{
    Start="//e:Data[@Name = 'BootStartTime']/text()"
    End="//e:Data[@Name = 'BootEndTime']/text()"
}
$ns = @{ e = "http://schemas.microsoft.com/win/2004/08/events/event" }

[DateTime]$Start = Select-Xml -Xml $xml -XPath $xpath.Start -Namespace $ns |
                   Select -Expand Node | Select -expand Value

[DateTime]$End = Select-Xml -Xml $xml -XPath $xpath.End -Namespace $ns |
                 Select -Expand Node | Select -expand Value

($End - $Start).ToString() # Displays: 00:03:11.7917783
 

Of course, you don’t have to use Select-Xml, you can do this in plain .Net without cmdlets (and this is what you would have to do in C#). In fact, depending on the situation, it might even be simpler:


$xpath = @{
    Start="//e:Data[@Name = 'BootStartTime']/text()"
    End="//e:Data[@Name = 'BootEndTime']/text()"
}

$ns = New-Object Xml.XmlNamespaceManager $xml.NameTable
$ns.AddNamespace( "e", "http://schemas.microsoft.com/win/2004/08/events/event" )

[DateTime]$Start = $xml.SelectSingleNode( $xpath.Start, $ns ).Value
[DateTime]$End   = $xml.SelectSingleNode( $xpath.End, $ns ).Value

($End - $Start).ToString() # Displays: 00:03:11.7917783
 

Selecting nodes regardless of namespaces

There are, however, two ways that you could avoid specifying the namespaces. The first is to just avoid specifying the node name at all. In that first example, that would be fairly easy, because the “BootStartTime” and “BootEndTime” names are unique to the nodes we’re interested in (even if there were boatloads of identical events, you’ll never have a Name=“BootStartTime” attribute on the tag, for instance). The second way is to filter using the local-name function, and specify just the “local” name (which is the non-namespace-qualified part of the name).

So to ignore the tag name, we can just use a * for a wildcard. The only real difference is that we don’t need the namespace, and the XPath pattern will be different:


$xpath = @{
    Start="//*[@Name = 'BootStartTime']/text()"
    End="//*[@Name = 'BootEndTime']/text()"
}

[DateTime]$Start = (Select-Xml -xml $xml $xpath.Start).Node.Value
[DateTime]$End   = (Select-Xml -xml $xml $xpath.End).Node.Value
($End - $Start).ToString() # Displays: 00:03:11.7917783
 

Or to specify the local name, we can use the Local-Name function. Again, we don’t need a namespace, we are just changing the XPath to be a more specific match:


$xpath = @{
    Start="//*[local-name() = 'Data' and @Name = 'BootStartTime']/text()"
    End="//*[local-name() = 'Data' and @Name = 'BootEndTime']/text()"
}

[DateTime]$Start = $xml.SelectSingleNode( $xpath.Start ).Value
[DateTime]$End   = $xml.SelectSingleNode( $xpath.End ).Value
($End - $Start).ToString() # Displays: 00:03:11.7917783
 

Reblog this post [with Zemanta]

Someone asked the question in #PowerShell (on irc.Freenode.net):

How do I find an item (in an array) based on one of it’s properties?

Actually, the question was rather more complicated than that. They were importing a bunch of users from a csv file, and wanted to sort them and search them based on a specific column. There are many ways to skin this cat. Imagine that you have a CSV file, and have imported it, like so:


Set-Content users.csv @"
LastName, FirstName, UserName, Url
Bennett, Joel, Jaykul, http://HuddledMasses.org
Rottenberg, Hal, HalR9000, http://halr9000.com
Hicks, Jeffrey, SapienScripter, http://blog.sapien.com/
"
@

$users = Import-Csv .\users.csv

Now, imagine that the CSV file has thousands of users in it, and that you need to not only sort the data by first name or last name on demand, but you also need to pull users from the list (by name) on demand.

These are trivial tasks in PowerShell: Read the rest of this entry »

To those of you who are not software developers: feel free to skip this post ;-)

A while ago I wrote a little class for calling console apps from a .Net application, and I’ve been using it in several of my apps (most notably in PoshConsole) and it works great, but since the only place I’ve really published it is in PoshConsole, I thought I’d write it up here, and share it with you …

Basically, it’s a slick invisible event-based wrapper around the Windows native console. What I mean is, it calls AllocConsole when it’s instantiated to create a native console, and hides the console window so it doesn’t show up. This allows you to run any console app you need to from within your app without having it popup a black window ;) Note this doesn’t let you run graphical consoles like EDIT.COM, but it can handle interactive apps like cmd.exe, batch files, or ftp.exe). All you really have to do is create one of my NativeConsole objects, handle its WriteOutputLine and WriteErrorLine events … and use its WriteInput method to send input or commands to the console app.

You can check out how it works in my WPF-based PoshConsole, and you can get the latest version of it from that project as well (it’s in \trunk\Huddled\Interop\NativeConsole.cs) but for now, here’s the single file source code, with a more liberal set of licenses than I allow for PoshConsole. Read the rest of this entry »

Well, Visual Studio 2008 launched while I was off in Houston, Texas … if you don’t have an MSDN subscription, you can check out Visual C# Express 2008 and the rest of the Visual 2008 Express editions, or the trial versions and of course, the new .Net Framework 3.5

Someone asked in the #PowerShell channel on FreeNode for a way to register dll’s (you know, old COM libraries for use in scripts or apps) ... specifically, they wanted to create a script that could register a bunch of Dll files, and know which ones passed or failed.

It turned out to be an interesting problem, because even though the source code on the MSDN Library has a /C parameter to cause the application to write to stdout, the one which comes with windows doesn’t, so the only obvious way to get output is in a MessageBox. However, there is also an exit code, but the exit code doesn’t seem to end up in $LASTEXITCODE or $? at all (maybe because the app is actually not a console app? I don’t get it, really). So the real problem became: how do I capture the exit code of an application in PowerShell?

[new] Someone sent me an email today (Jan 7 2010) mentioning that if you nest your call to regsvr32 inside a call to cmd.exe … it does set the $LastExitCode:

cmd /c "regsvr32 /s 'C:\Path\To\Some.dll'"
$LastExitCode ## Will be set correctly.

Well, the simplest thing would be to just go around that — to compile and distribute the MSDN sample with the /c console output option so I don’t need the exit code. Of course, they are very clear that we shouldn’t do that because the sample isn’t “safe,” and distributing it afterward would probably be a problem with licensing. Well, I don’t know about that, but I figured the best thing would be to just use the exit code from the existing RegSvr32.exe rather than asking people to use what they would perceive as a 3rd party RegSvr32.

And if we play around a bit with the .Net Process and ProcessStartInfo classes, it’s not to hard to get the exit code …


#### Get-ExitCode.ps1
##########################################################
# initialize things
$p = new-object System.Diagnostics.Process
$si = new-object System.Diagnostics.ProcessStartInfo
$exit = $false

# split off the first argument (the command) from any others
$si.FileName, $si.Arguments = $args

$p.StartInfo = $si
if( $p.Start() ) {
  $p.WaitForExit()
  $exit = $p.ExitCode
}
$p.Dispose()
$exit
 

After a bit more experimentation with the return values, I came up with a function called RegisterDllServer which appears below. The function has a -Verbose switch and a -Debug switch which turn on some helpful messages (the Debug switch actually allows the RegSvr32 message boxes to show up, so you shouldn’t use that if you’re calling it from within a script). Read the rest of this entry »

Microsoft has published a new Command Line Standard which sets out the standard for writing command line applications for Microsoft platforms … While it’s clearly based on the way they’ve written PowerShell, it is a spec that is “independent of any specific implementation of a shell, set of utilities or command creation technologies” and should be used for any command line interface apps for DOS, too (especially since doing so would enable your app to function in a PowerShell pipeline as well).

Anyway, it looks really interesting, and I can’t help but think that perhaps the Linux command-line could benefit from apps implementing this standard too ;-) . In particular, I like the TCSV format option as a way of enhancing plain old CSV data with type and structure information … and the standardized naming convention. Ultimately, these five points (from the spec) should be the standard for any command-line interface (although I know many linux die-hards will note they’ve been living without number five for many years):

  1. Consistent verb and parameter naming conventions.
  2. Consistent command syntax
  3. Common behaviors.
  4. Consistent error messages and exit codes.
  1. Schema-enhanced data streams and formatting.

However, Appendix A – Standardized Verb Sets and Verb Names got my attention in particular, because it actually obsoletes a few of the Verbs that were in this list on the PowerShell blog and which they’ve actually been using in the Community Extensions … Specifically, Write is marked as obsolete in favor of Set — and it’s pair Get, is to be used instead of the obsolete Read. In addition, there’s no mention of Out and *Where* is only mentioned as an obsolete version of Resolve (which really made me wonder about “Where-Object” but I guess that can be the exception that proves the rule?). The spec actually says that it is required to use verbs from the list of standard verbs in Appendix A., so there doesn’t seem to be an option to invent your own verbs.

If you have any comments about the spec, I guess you should put them on this post on their blog, rather than on this thread in the PSCX forum.

I’ll have to write another post on this later, after I’ve had a chance to re-read the spec and digest it a bit … so far it looks really good, but it sure would throw the monkey-wrench in my old console “Hello World” apps in C++ and Java … I wonder if someone will create a wrapper to make writing compliant command line apps easier (without resorting to writing PowerShell commandlets which are practically compliant automatically). I also wonder how long it will be until a new PowerShell release comes out that actually understands TCSV...

[New] CodePlex Project

As I announced recently I have created a Windows Automation PowerShell Snapin project to house this snapin on CodePlex, and added a bunch of features. You should head over there for the download.

Original Post

I’ve been crazy busy the last few weeks, but I’ve been really rather distracted from my main project and it’s past time I got back to it. To really feel like I’ve moved on, I need to write a bunch of articles here and publish a couple of cool apps and some source code so that I can feel like I’ve reached a release point. What I’ve been playing with in all this coding is the new technology that’s been coming out of Microsoft in the last couple months: PowerShell, .NET 3 and WPF, and Windows Vista so you may or may not actually be able to use these apps …

So yeah, anyway … I’ve been playing around with PowerShell cmdlets, and as a shell geek, I couldn’t help wondering why there wasn’t a way to enumerate windows and move them around … so I wrote one. Eventually this will show up in the PowerShell Community Extensions — but I’m posting it here for now because the powershell cmdlet process is pretty interesting.

I started off by writing a wrapper for some of the Win32 APIs, and then a PSSnapIn which provides Get-Window and Remove-Window. When you execute Get-Window, the resulting object is a Win32.Window which has methods for closing, moving, resizing, maximizing and restoring, etc. The Remove-Window cmdlet is just a wrapper to call the Close() method, but it seems to make sense in the PowerShell pipe, since you can pipe the window objects through filters etc.

I still need to finish up the Move-Window cmdlet — it’s an advanced window-organizing feature. Right now it’s only feature is that it can tile windows vertically or horizontally with percentages specified by you. The features there are a little weak, but it’s past time I show you what I mean.

What you would want to do is install the snapin and then try typing these commands one at a time (so you can see the results).


for( $i = 0; $i -lt 3; $i++){notepad}
Get-Window *notepad* > Notepad.txt
notepad Notepad.txt
Get-Window "Untitled - N*" | Move-Window "20%,30%,50%"
ps notepad | Move-Window "20%,30%,20%,30%" 0
(Get-Window *Notepad.txt*).Minimize()
$notes = Get-Window *notepad*
$notes[0].Minimize()
Get-Window | where {$_.ProcessName -eq "notepad" -and -not $_.IsMinimized} | Remove-Window
ps notepad | Remove-Window
 

A little explanation is in order:

  • Obviously the first three lines basically start up a few copies of notepad — three of them empty, one with a text file.
  • The next line shows how Get-Window works with wildcard matching on the window titles … and how Move-Window uses percentage values to organize windows.
  • Then you see that you can pipe the output of Get-Process (aliased as ps) through Move-Window. You can pipe it through Get-Window too, but the important take away here is that Remove-Window and Move-Window can both take processes as input — as long as those processes have actual windows. You’ll also notice that final parameter “0” to cause Move-Window to tile horizontally instead of vertically — “1” is the default.
  • The next three lines are examples of how you can call methods on individual Window objects.
  • And finally, the next-to-last line is just an example of how you can use Where-Object to filter windows, and the last line is just to get rid of the remaining instances of notepad.

You can download Win32.Window for PowerShell (it’s a 7-zip file, you’ll need TugZip or 7-Zip) ... it includes the source (which you can use under any of several open source licenses including Ms-PL, BSD and GPL) and the actual DLL in the bin/Release directory, along with the scripts Install.ps1 and Uninstall.ps1 ;)

Feature requests and code contributions are both welcome!

The inaptly named Windows RSS Platform is actually part of IE7, not part of Windows, and therefore is available on Windows XP if IE 7 has been installed, as well as on Windows Vista (where IE 7 is included originally). However, having said that, it isn’t just for IE: it includes a complete COM API which is usable from script or the .Net Framework, and the header files are part of the Windows Platform SDK and usable from C/C++.

The RSS Platform is intended to introduce a unified approach to RSS for Windows applications, where all applications use the same RSS feed store, and a service handles downloading the RSS feeds — including enclosures if requested — and normalizes them so applications need not handle parsing all the different feed formats (that is, you only need to parse the Microsoft-normalized RSS 2.0 with extensions).

As a platform for building RSS-based applications, it’s very well done, and well thought out. It’s now ridiculously easy to create an RSS reader, since the platform removes all need to parse XML except in the weirdest situations, and allows all applications to be instantly integrated on the same list of RSS feeds … let me show you …. Read the rest of this entry »

Search My Content