Windows Vista Forums
Vista Forums Home Join Vista Forums Donate Vista Tutorials Tags

Welcome to Vista Forums we are your forum to discuss Windows Vista x64 and x86 systems. Whether you need help or just want to post an idea you have on Vista, this is the forum for you.
Register at Vista forums...the world biggest Windows Vista resource Join Vista Forums Now

Go Back   Vista Forums > Microsoft Technical Newsgroups > PowerShell

Cmdlet Parameter Binding Question

Update your Vista Drivers Update Your Drivers Now!!
Closed Thread
 
Thread Tools Display Modes
Old 12-09-2006   #1 (permalink)
Keith Hill [MVP]
Guest


 

Cmdlet Parameter Binding Question

With my Get-Hash cmdlet I have a string[] Path property that can be bound to
the pipeline allowing me to use the cmdlet like this:

dir *.exe | get-hash

However this seems to preclude me from doing this:

"c:\boot.ini" | get-hash

Where I want to hash the string and not the file c:\boot.ini. Is this just
a case of you can't have your cake and eat it too? Is there a way to force
the string to bind to the "Object" parameterset instead of the "Path"
parameterset?

BTW trying to do what I want here probably isn't a good idea because it
requires me to pick an Encoder to convert the string to a byte[] for
hashing. That presumes I can easily find out the encoding a string which I
can't. Does someone know of a .NET framework trick to figure this out?
IIRC this is a fundamentally difficult problem. Save the string " abc.bak
abc.txt" without the quotes in notepad sometime (use ASCII encoding) and
then reload it. Interesting. Raymond Chen has a nice write-up on this at:

http://blogs.msdn.com/oldnewthing/ar.../24/95235.aspx

--
Keith



My System SpecsSystem Spec
Old 12-09-2006   #2 (permalink)
Maximilian Hänel
Guest


 

Re: Cmdlet Parameter Binding Question

Hi Keith,

> BTW trying to do what I want here probably isn't a good idea because it
> requires me to pick an Encoder to convert the string to a byte[] for
> hashing. That presumes I can easily find out the encoding a string which I
> can't. Does someone know of a .NET framework trick to figure this out?


In .NET a string is _always_ Unicode. It's not possible to say this
string should be ASCII and that UTF8 or the like. It's up to you to load
the right bits into the string by using the appropriate Encoding when
opening a file or using Encoding.GetChars. But once it's loaded the
string is treated as Unicode. So it doesn't make sense to ask what
encoding a string has - it's Unicode.

So this leads to the question of how to figure out the encoding of a
file. Well, if it does not have a BOM you are lost. Regardless of how
smart an algorithm for automatically figuring out a files encoding is,
at the end this algorithm must guess.

So when it comes to calculate the Hash you should always treat a file as
a binary. If you get a string then this string is unicode, period. If
one wants the hash of a ASCII or whatever string then the _caller_ must
provide the appropriate byte representation and pass it as a byte array,
because only the caller knows what he wants.

hth

Max
My System SpecsSystem Spec
Old 12-09-2006   #3 (permalink)
Keith Hill [MVP]
Guest


 

Re: Cmdlet Parameter Binding Question

"Maximilian Hänel" <ngSpam@smjh.de> wrote in message news:%23SOG4x4GHHA.1276@TK2MSFTNGP04.phx.gbl...
> So when it comes to calculate the Hash you should always treat a file as
> a binary. If you get a string then this string is unicode, period. If
> one wants the hash of a ASCII or whatever string then the _caller_ must
> provide the appropriate byte representation and pass it as a byte array,
> because only the caller knows what he wants.


Re .NET strings and encoding, doh! That was a sleep deprivation induced brain fart. :-(

So string would be nice to be nice accept as pipeline input except that my Path parameter is of type string[] so that someone can pass in a string that is a path to a file to hash. Because the type is string it gets mapped to the Path parameter. This is how the various *-item cmdlets work. You can pass them a FileInfo, any object with a Path/PSPath property or a *string* path via the pipeline. In general I think it is useful to be able to operate on files via a string path, say perhaps you have a file containing a list of paths to get hashes of. Of course, you can bypass the parameter/type mapping by using -InputObject. Does this seem like a reasonable way to operate directly on strings?

2> "abcdefghijklmnopqrstuvwxyz" | get-hash -InputObject {$_}


Path :
Algorithm : MD5
HashString : 35020D67A52D8E915330F0A77F676BBF
Hash : {53, 2, 13, 103, 165, 45, 142, 145, 83, 48, 240, 167, 127, 103, 10
7, 191}

I guess it depends on whether it is going to be more common for folks to want to hash files or strings. Opinions?

--
Keith
My System SpecsSystem Spec
Old 12-09-2006   #4 (permalink)
Adam Milazzo
Guest


 

Re: Cmdlet Parameter Binding Question

Keith Hill [MVP] wrote:
> Does this seem like a reasonable way to operate directly on strings?
>
> 2> "abcdefghijklmnopqrstuvwxyz" | get-hash -InputObject {$_}


Does this not work?

get-hash -InputObject "abcdefghijklmnopqrstuvwxyz"

I think hashing strings could be useful, but the most common case will
be hashing files.

I think:

get-hash "foo" should hash a file named foo
get-hash -InputObject "foo" should hash the string foo

"foo" | get-hash ... I'm not 100% sure, but I think it should also hash
the string "foo", if that's possible to do...


And regarding hashing strings, I'll make a small clarification.

Max wrote "So it doesn't make sense to ask what encoding a string has -
it's Unicode."

Actually, .NET strings do have an encoding, which is UCS-2
(system-endian). This makes it a bit tricky if you want to hash them,
because the string's raw stream of bytes is different on little-endian
and big-endian systems.

I guess I would recommend that you allow the user to override the
encoding, but choose a default, like little-endian UCS-2 (which
corresponds to Encoding.Unicode) when you convert the string to bytes.
My System SpecsSystem Spec
Old 12-09-2006   #5 (permalink)
Adam Milazzo
Guest


 

Re: Cmdlet Parameter Binding Question

Adam Milazzo wrote:
> I guess I would recommend that you allow the user to override the
> encoding, but choose a default, like little-endian UCS-2 (which
> corresponds to Encoding.Unicode) when you convert the string to bytes.


Correction, apparently Encoding.Unicode is little-endian UTF-16, not
little-endian UCS-2. Although .NET strings are still stored in memory as
system-endian UCS-2, as I said.

So there's probably no way to get the little-endian UCS-2 bytes except
to do it yourself. It's not too hard:

byte[] bytes = new byte[str.Length*2];
for(int i=0,j=0; i<str.Length; j+=2,i++)
{
char c = str[i];
bytes[j] = (byte)(c&0xFF);
bytes[j+1] = (byte)(c>>8);
}

This should work correctly on little-endian systems. For big-endian
systems, just swap "c&0xFF" and "c>>8". You can determine the current
endianness using BitConverter.IsLittleEndian.

Then again, you might just use Encoding.Unicode as the default anyway
and forget about UCS-2. I guess it doesn't really matter what you use as
the default, as long as it has a fixed endian-ness so the hash is the
same on big-endian and little-endian machines...
My System SpecsSystem Spec
Old 12-10-2006   #6 (permalink)
Keith Hill [MVP]
Guest


 

Re: Cmdlet Parameter Binding Question

"Adam Milazzo" <adamm@san.rr.com> wrote in message
news:%23d7OYlBHHHA.1264@TK2MSFTNGP03.phx.gbl...
> Keith Hill [MVP] wrote:
>> Does this seem like a reasonable way to operate directly on strings?
>> 2> "abcdefghijklmnopqrstuvwxyz" | get-hash -InputObject {$_}

>
> Does this not work?
>
> get-hash -InputObject "abcdefghijklmnopqrstuvwxyz"
>


Yeah that is the way to do it. No obvious but not hard either.


> "foo" | get-hash ... I'm not 100% sure, but I think it should also hash
> the string "foo", if that's possible to do...


That's not easy because the -Path parameter is type string[] and PoSh
helpfully takes that input and populates the Path property.

--
Keith


My System SpecsSystem Spec
Old 12-10-2006   #7 (permalink)
Jacques Barathon [MS]
Guest


 

Re: Cmdlet Parameter Binding Question

"Keith Hill [MVP]" <r_keith_hill@mailhot.moc.nospam> wrote in message
news:%232v0O%233GHHA.1240@TK2MSFTNGP03.phx.gbl...
> With my Get-Hash cmdlet I have a string[] Path property that can be bound
> to the pipeline allowing me to use the cmdlet like this:
>
> dir *.exe | get-hash
>
> However this seems to preclude me from doing this:
>
> "c:\boot.ini" | get-hash
>
> Where I want to hash the string and not the file c:\boot.ini. Is this
> just a case of you can't have your cake and eat it too? Is there a way to
> force the string to bind to the "Object" parameterset instead of the
> "Path" parameterset?


Disclaimer: I am not a developer (well, I used to but that was pre-history)
and I never tried to write any cmdlet.

dir *.exe | get-member
.... returns [System.IO.FileInfo] objects.

So, why don't you create two parameter sets in your cmdlet? One would accept
a [System.IO.FileInfo][] property to handle files and the other would accept
a [System.String][] property to handle strings.

Jacques

My System SpecsSystem Spec
Old 12-10-2006   #8 (permalink)
Jacques Barathon [MS]
Guest


 

Re: Cmdlet Parameter Binding Question

"Jacques Barathon [MS]" <jbaratho@online.microsoft.com> wrote in message
news:emWwvdCHHHA.4116@TK2MSFTNGP05.phx.gbl...
<...>
> So, why don't you create two parameter sets in your cmdlet? One would
> accept a [System.IO.FileInfo][] property to handle files and the other
> would accept a [System.String][] property to handle strings.


Very basic implementation in a filter (functions, filters and scripts don't
implement parameter sets but they can verify their parameter types so that
we can sort of emulate the functionality):

PS> filter test-hash {
>> if ($_ -is [System.IO.FileInfo]) {"Handling $_ as a file..."}
>> else {if ($_ -is [System.String]) {"Handling $_ as a string..."}}
>> }
>>

PS> "hello"|test-hash
Handling hello as a string...
PS> dir *.exe|test-hash
Handling C:\Users\jbaratho\Documents\Private\test\notepad.exe as a file...
Handling C:\Users\jbaratho\Documents\Private\test\regedit.exe as a file...
Handling C:\Users\jbaratho\Documents\Private\test\sid2name.exe as a file...

Jacques

My System SpecsSystem Spec
Old 12-10-2006   #9 (permalink)
Maximilian Hänel
Guest


 

Re: Cmdlet Parameter Binding Question

Hi Adam,

> So there's probably no way to get the little-endian UCS-2 bytes except
> to do it yourself. It's not too hard:


But does it make sense to calculate a strings hashcode platform
dependend? At least to me it makes much more sense to calculate the
hashcode of a .NET string in a consistent manner. So it's probably
better to use Encoding.Unicode.GetBytes() for the hash calculation. As I
already mentioned: If one wants the hashcode of a different byte
representation then the caller should provide that byte sequence.

> Then again, you might just use Encoding.Unicode as the default anyway
> and forget about UCS-2. I guess it doesn't really matter what you use as
> the default, as long as it has a fixed endian-ness so the hash is the
> same on big-endian and little-endian machines...


Ok, I should first read the full posting before writing any comments ;-)

cu

Max
My System SpecsSystem Spec
Old 12-10-2006   #10 (permalink)
Maximilian Hänel
Guest


 

Re: Cmdlet Parameter Binding Question

Hi Keith,


> Of course, you can bypass the parameter/type mapping by using
> -InputObject. Does this seem like a reasonable way to operate directly
> on strings?
>
> 2> "abcdefghijklmnopqrstuvwxyz" | get-hash -InputObject {$_}


I like this idea and it's also very consistent with other CmdLets. Just
take a look at the Select-String CmdLet. A string is always treated as a
path as long as you don't tag it as an InputObject.
The nice thing about this is, that one could then write:

PS > Get-Hash *.ps1,*.cs | Select HashString, Path | Out-File FileList.txt

btw a FileName/Name property would be a nice thing, too. Returns, well -
the file name without the path ;-)

PS > Get-Hash *.ps1,*.cs | Select HashString, Name | Out-File FileList.txt

> I guess it depends on whether it is going to be more common for folks to
> want to hash files or strings.


Files, no question (to me ;-) ).

cu

Max
My System SpecsSystem Spec
Closed Thread

Thread Tools
Display Modes



Similar Threads
Thread Thread Starter Forum Replies Last Post
CTP: Script cmdlet parameter attributes error Shay Levi PowerShell 6 12-12-2007 01:52 AM
cmdlet parameter sets Darren Mar-Elia PowerShell 13 11-08-2007 06:41 AM
Style of cmdlet parameter names Roman Kuzmin PowerShell 3 12-24-2006 01:50 PM
Cmdlet Parameter Positon Keith Hill [MVP] PowerShell 2 11-23-2006 02:31 PM
Alias name in parameter prompt instead of cmdlet name Jouko Kynsijärvi PowerShell 3 05-23-2006 06:19 PM


Update your Vista Drivers Update Your Drivers Now!!

Vistax64.com is an independent web site and has not been authorized,
sponsored, or otherwise approved by Microsoft Corporation.
"Windows Vista", the Start Orb, and related materials are trademarks of Microsoft Corp.
© Designer Media 2005-2008