/\/\o\/\/ PowerShelled

This blog has moved to http://ThePowerShellGuy.com Greetings /\/\o\/\/
$AtomFeed = ("Atom.xml")
$PreviousItems = (" Moving to ThePowerShellGuy.com "," PowerShell Code formatting test for my new Blog "," PowerShell Code formatting test for my new Blog "," PowerShell Community Extensions V1.0 "," PowerShell : Access remote eventlogs "," Windows PowerShell Scripting Sweepstakes! "," PowerShell : making Custum Enums "," TechNet Webcast: An Overview of Windows PowerShell "," "Windows PowerShell: TFM" goes "Gold" "," PowerShell : Advanced renaming of files "," ")

Tuesday, November 29, 2005

 


Logging your MSH session



It's Easy to log a session in MSH,

you just use start-transcript and stop-transcript.

MSH>gc "C:\Documents and Settings\mow\My Documents\msh_transcript.20051129213303.txt"
**********************
MSH Transcript Start
Start time: 20051129213303
Username : CP340339-A\mow
Machine : CP340339-A (Microsoft Windows NT 5.1.2600 Service Pack 2)
**********************
Transcript started, output file is C:\Documents and Settings\mow\My Documents\msh_transcript.20051129213303.txt
MSH>stop-transcript
**********************
MSH Transcript End
End time: 20051129213308
**********************


You may have seen the big list of supported date formats in last post, that we could parse to a date-object ....

Now ....guess what .... this one was not on the List ;-(

So An example of using -Match and [dateTime]::Parse to get a "real" date from the used dateformat in the Logfile :

MSH>"20051129213308" -match "(....)(..)(..)(..)(..)(..)"
True
MSH>[Datetime]::parse([string]::join("-",$matches[1..3])+"T"+[string]::join(":",$matches[4..6]))

Tuesday, November 29, 2005 9:33:08 PM


so now you have a "real" date object to work with,
the regex is a bit lazy becouse I just used "." (any Char), ofcourse its better to check on Digits, just liked the example of using -match (b.t.w. could not do this with Match-string) and then using the Matches with a RangeOperator, showing the flexbility there.

*edit* Sorry, another Edit in 5 minutes but I realy did think I was to lazy,
here is the "better" version (checking for digits) :

MSH>"20051129213308" -match "(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})"
True
MSH>[Datetime]::parse([string]::join("-",$matches[1..3])+"T"+[string]::join(":",$matches[4..6]))

Tuesday, November 29, 2005 9:33:08 PM


but normal I still think I would prefer a RegEx-Object for this work.
e.g.:

$regex = new-object System.Text.RegularExpressions.regex("pattern")


You can than use the Replace Method of it, also I had a bit of problems with match-string doing this.
and the replace flexibility I like, also I know it a bit better from .NET and VBScript.But I did not play with match-string enough yet to make it final ;-), and I think the RegEx does deserve a blog entry on his own (altough you can find a lot of info on using regEx, already just try a Search in google)

anyway for small checks -match is ideal, and seems to work better as match-string.

Ohh, and yeah this was about logging, that works easy in Monad, altough I would have picked another date format for it ;-)

gr /\/\o\/\/


 2 comments

Monday, November 28, 2005

 


MSH get-dateFormat function



I very handy function to get the current datetime Formats,
(finaly an end to all those trips to the controlpanel )


Function get-DateFormat{[System.Globalization.CultureInfo]::CurrentCulture.DateTimeFormat | select *Pattern}



I found the tip here : James Manning's blog,
What formats can I specify for date/time with the tf.exe command-line?

thank's alot that's another one for my toolbox ;-)


MSH>get-dateformat


FullDateTimePattern : dddd, MMMM dd, yyyy h:mm:ss tt
LongDatePattern : dddd, MMMM dd, yyyy
LongTimePattern : h:mm:ss tt
MonthDayPattern : MMMM dd
RFC1123Pattern : ddd, dd MMM yyyy HH':'mm':'ss 'GMT'
ShortDatePattern : M/d/yyyy
ShortTimePattern : h:mm tt
SortableDateTimePattern : yyyy'-'MM'-'dd'T'HH':'mm':'ss
UniversalSortableDateTimePattern : yyyy'-'MM'-'dd HH':'mm':'ss'Z'
YearMonthPattern : MMMM, yyyy


Also, as we are at dateformats now,
A nice one to try also :



(get-date).GetDateTimeFormats()


Pick one ;-)

*edit* as I just posted this I did think about that last command, and did think there should be a more "native" way to do this , and Yes ;-)

MSH>(get-UICulture).get_DateTimeFormat()


AMDesignator : AM
Calendar : System.Globalization.GregorianCalendar
DateSeparator : /
FirstDayOfWeek : Sunday
CalendarWeekRule : FirstDay
FullDateTimePattern : dddd, MMMM dd, yyyy h:mm:ss tt
LongDatePattern : dddd, MMMM dd, yyyy
LongTimePattern : h:mm:ss tt
MonthDayPattern : MMMM dd
PMDesignator : PM
RFC1123Pattern : ddd, dd MMM yyyy HH':'mm':'ss 'GMT'
ShortDatePattern : M/d/yyyy
ShortTimePattern : h:mm tt
SortableDateTimePattern : yyyy'-'MM'-'dd'T'HH':'mm':'ss
TimeSeparator : :
UniversalSortableDateTimePattern : yyyy'-'MM'-'dd HH':'mm':'ss'Z'
YearMonthPattern : MMMM, yyyy
AbbreviatedDayNames : {Sun, Mon, Tue, Wed, Thu, Fri, Sat}
ShortestDayNames : {Su, Mo, Tu, We, Th, Fr, Sa}
DayNames : {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday}
AbbreviatedMonthNames : {Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec, }
MonthNames : {January, February, March, April, May, June, July, August, September, October, November, December, }
IsReadOnly : True
NativeCalendarName : Gregorian Calendar
AbbreviatedMonthGenitiveNames : {Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec, }
MonthGenitiveNames : {January, February, March, April, May, June, July, August, September, October, November, December, }


gr /\/\o\/\/


posted by /\/\o\/\/
 2 comments
 


Working with a Path in MSH



In Monad there are some handy tools to work with a path,

I want to mention some I think are the most handy here.
Also I get to the differences between a path in MSH and in CMD, as in MSH it’s not always a disk we are referring to here, but more about that later.

First test-path

Test-path does what the most of you are used to do with IF EXIST in batch files.


MSH>test-path c:\test
True
MSH>test-path c:\foo
False
MSH>test-path c:\test\*.txt
True
MSH>test-path c:\test\* -ex *.txt
True
MSH>test-path c:\test\*.* -ex *.txt
False


The last 2 are interesting, the question asked to test-path is here :
The first is Does c:\test contain any Items other then text files ?
(in my case there was a subdirectory of test)

Then I nice one I found in Resolve Path
what does this do ?


resolve-path ~
resolves the users Home directory ;-)
(I don’t know where the ~ comes from, It does not work on his own, nor have I seen it anywhere else yet.)


MSH>resolve-path ~

Path
----
C:\Documents and Settings\mow

And another nice one :


MSH>resolve-path ~).drive.CurrentLocation
Test
get the current location on the drive(provider) where the homedirectory is.
Very useful ;-)
But more serious .. the point here is that you get access to the Drive Object …
And you can also use wildcards here to get more objects back.


MSH>resolve-path g:\mon*\t*\*.*

Path
----
G:\Monad\test...test\test.xml
G:\Monad\txt\com.txt
G:\Monad\txt\count.txt
A bit more usefull ?

Combine-path


MSH>combine-path c:\test\ \monad
c:\test\monad
MSH>combine-path c:\test\ /monad
c:\test\monad


as you can see in this example this is more safe than just to use a string for this, as this class has some logic (it sees that both parts contain the delimiter and removes one)

Also, remember a drive in Monad is actually a Provider, so to be save use the combine-path command for this, then you use the MshPath as the glue, (This is also the wrapper that provides the use of / in MSH), before use the path gets resolved to a format the Provider is familiar with.

See also the difference here :


MSH>(gi .).MshPath
FileSystem::C:\Test
MSH>cd hklm: ; (gi .).MshPath
Registry::HKEY_LOCAL_MACHINE
MSH>pwd

Path
----
HKLM:
MSH>convert-path (pwd)
HKEY_LOCAL_MACHINE\


So convert-path will give you the path as it is presented to the provider.

I only tipped at some of the uses of the Path commandlets and the difference between a path in MSH and in CMD, i would reccomend you look at there help a bit, and in the beta documentation (see $links), and I would like to give you some other examples of working with a path in MSH.


MSH>pwd

Path
----
C:\Test\Monad


MSH>(pwd).path
C:\Test\Monad
MSH>(pwd).path.length
13
MSH>(gi .).root.name
C:MSH>(gi .).parent.name
Test
MSH>(gi .).parent.name.StartsWith("t")
False
MSH>(gi .).parent.name.StartsWith("T")
True





maybe some thinks will look a bit strange at first, but if you play a bit with them they are prety powerfull tools,

Some Tips are don't think to much filesystem think Provider and don't use test parsing if you don't realy need it (think Oject ;-).
As always with Monad using get-member a lot will help also .

Enjoy,

Gr /\/\o\/\/


posted by /\/\o\/\/
 0 comments

Sunday, November 27, 2005

 


MSH MSN Instant messenger project (broken off)



after reading this blog Item, Use IM to Ask Encarta i did think that would be cool to do in MSH.

I started with the library dotMSN, you can find here :

http://www.xihsolutions.net/dotmsn/

I just downloaded the DLL imported it in MSH and got started :



[System.Reflection.Assembly]::LoadFile("g:\monad\dll\XihSolutions.DotMSN.dll")

$im = new XihSolutions.DotMSN.messenger
$im.Credentials.Account = "User@hotmail.com"
$im.Credentials.Password = "Password"
$im.Credentials.ClientID = "msmsgs@msnmsgr.com"
$im.Credentials.ClientCode = "Q1P7W2E4J9R8U3S5"
$im.connect()
$im.add_ConversationCreated({write-host "Created"})
$con = $im.CreateConversation()
$con.invite(encarta@conversagent.com)

the ClientID and Code are Fixed(imitating the real MSN client), I got them from the Example

easy enough till here ;-), and it get's all contacts for you already.

But I came to some problems with requesting a swithboard here.
http://www.xihsolutions.net/dotmsn/api/XihSolutions.DotMSN.NSMessageHandler.SwitchboardQueueItem.Initiator.html

but if you download the Full package, there is a working example.
So I started to test with that, then I got this answers from Encarta :

* Encarta® Instant Answers joined the conversation

You say: who is the pope ?
Encarta® Instant Answers says: Which country or state would you like to know about?

You say: who is the queen of the netherlands ?
Encarta® Instant Answers says: I don't know about the Queen of the Netherlands, but I do know that the ruler of the Netherlands is German occupation.

Ok, as I never used MSN before and did only sign-up for this I keep it with that, and go to play some chess ;-)

but I still decided to post this as it already gets all the contact's, as MSH objects, for me that's only one so not very usefull , but if you use MSN a lot, maybe this alone is enough already ;-)
as you can use MSH filters on then etc.

MSH>$im.contactlist.All


MobileDevice : False
MobileAccess : False
HomePhone :
WorkPhone :
MobilePhone :
ClientCapacities : 0
Mail : encarta@conversagent.com
Name : Encartar Instant Answers
Status : Offline
Online : False
NSMessageHandler : XihSolutions.DotMSN.NSMessageHandler
DisplayImage :
Emoticons : {}
ClientData :
ContactGroup : XihSolutions.DotMSN.ContactGroup
Blocked : False
OnBlockedList : False
OnForwardList : True
OnAllowedList : True
OnReverseList : False

so if you need to do some cleaning on your contacts in MSN, you can use MSH for this in this way.

and maybe someone is interested in finishing it in MSH, but as I don't use MSN for the rest, and encarta keeps on pointing me out to start the encarta application also, I decided to quit here for now.

but I hope this is still of use for someone more in to IM as I am, as the used library is pretty good, and is worth checking out I think.

gr /\/\o\/\/


posted by /\/\o\/\/
 0 comments

Saturday, November 26, 2005

 


Running (Un-block) a downloaded script in MSH



I got a comment of Lee Holmes, on last post. Tipping that you can also use time-expression, to time operations in MSH.

eg:

time-Expression {sleep 1}

Seconds : 1
Milliseconds : 5

time-Expression {sleep 1}

Seconds : 1
Milliseconds : 3

time-Expression {sleep 1}

Seconds : 0
Milliseconds : 999

(the output contains more (day,s hours etc., but I let it out here)
it also shows a good example of the "Caching" I mentioned about in last blog, if you do the same action a couple of times it get quicker. (last example even a bit to quick ;-)

after looking at his blog and finding Part 2 of the Burn-Console series, I also posted about before : burn-console.msh Part II - A working implementation , I think I did see, why he is into timing also ;-), you will see if you look there.

but to get back to the topic,

ofcource, I was eager to try his new Example, I downloaded it (the TXT file as pasting gives some troubles) , removed the .TXT part and started it (at least tried to) :

MSH>.\burn-console-1.working.msh

The file G:\Monad\burn-console-1.working.msh cannot be loaded. The file G:\Monad\burn-console-1.working.msh is not digitally signed. The script will not execute on the system. Please see "get-help about_signing" for more details..
At line:1 char:28
+ .\burn-console-1.working.msh <<<< href="http://mow001.blogspot.com/2005/10/codesigning-in-monad-shell-beta-2-for.html">CodeSigning in Monad" Shell Beta 2 (for .NET Framework 2.0 RC/RTM) , b.t.w. that will bring you also to Lee Holmes Blog, for a good item about this.

so I had to Un-Block it first (as Monad does know I got it from the internet) "hmm did think, I did not even tell my mother that, but ok ...;-)":

So I did right-click the file in explorer, and yes there was the Unblock button.

I unlocked the file, and did try to start it again.

same error.

???

But after starting a new MSH shell, Monad did know I "accepted" that script and did start it for me.

So it seems that this get's not updated / inspected again in the "live" MSH shell, you have to start a new shell to be able to start the script.

if you know it it's not that bad, but it can be confusing, so I hope this is a beta thingie.

Enjoy your downloaded (and startable) MSH scripts

gr /\/\o\/\/


posted by /\/\o\/\/
 1 comments

Friday, November 25, 2005

 


Timing the loading of your profile in MSH



I got a question on the last post how long my profile took to load.
I did not know but answered a bit less as a second (my MSH startuptime that is), and that this profile was still almost "clear".

but ofcourse it's is a good question, as you will notice this everytime you start-up MSH, and it's good to have a baseline for this.

To see what only the profile is doing, you can just put a stopwatch on it.

Start the profile.MSH with this :

$sw = new-object System.Diagnostics.Stopwatch
$sw.start()

and end with this :

$sw.stop()

then you can alway check on that $SW object later in the session, to see what the load time of the profile was.
and you can play with some items by remarking them in the profile so they are not processed and look what the effect is, so you can figure out what are the "expensive" items in it, .

for example the script as is now :

With .NET Ojects (Form and Clip)

MSH>$sw

IsRunning Elapsed ElapsedMilliseconds ElapsedTicks
--------- ------- ------------------- ------------
False 00:00:00.3216985 321 965147137

Without :

MSH>$sw

IsRunning Elapsed ElapsedMilliseconds ElapsedTicks
--------- ------- ------------------- ------------
False 00:00:00.1229599 122 368899440

also the drive workaround toke some time (not the functions as they are just declared)

b.t.w. you should measure a couple of time with the different settings, as the load time depents also on if it's the first time the Code gets loaded or the load of the computer at the time (also I noticed if you leave a shell for 12 hours or so, it will take some time to startup again (re-loading some .NET Obectes that are GC-ed ?)

so make shure your measurements are related, as they can differ if the status of the system changes between measurements, or the time between starting the MSH sessions, even if the settings do not change.

now you can check-up on your profile now and then to see if it still lives up to your start-time demands .


gr /\/\o\/\/


posted by /\/\o\/\/
 1 comments

Thursday, November 24, 2005

 


Tuning MSH in your Profile



In this blogentry I show you part of my profile, (and in the process a list of the previous entry’s most usefull for tuning MSH) to give an example how to set MSH to your own needs.

But First an update to the Minesweeper sample, MSH Minesweeper GUI game , as it more or less started this subject.

You need to load the Windows forms Library for it to work :

[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")

If you do not, you get a bunch of errors, I forgot to include the line in the script, this was partly a mistake, as some users can not run the script, see all the errors and will give up.
This issue was already mentioned earlier to me by martin but I have problems with updating. If you did read more of the blog before, you might know why, I still have a problems with my Pipelines if I edit the post I will lose them again. They are difficult to find, so I could mess it even more up by editing (I decided to add a comment).

But why I say partly ?

That’s because normally I would not need this in my script because it’s already loaded.
As it gets loaded in my profile, and it’s no use to load it again, so it was a mistake on the blog but not in the script (or was it ? ;-) ).

That is why I did not notice it was missing in the script when I did post it, I remember myself commenting it on another blog before so I think I’m not the only one where this is the case, there are chances that you also did not notice it. (for example if you have the MSH Object Viewer in your profile ot just did run it before in the session, as that was the case in my situation or another script that uses it.)

But anyway this made me decide to put some more info about the tuning I did in the MSH Profile.

There is an excellent blogitem about the Profiles and there locations in MSH here :

http://tfl09.blogspot.com/2005/10/customising-monad-via-profile-files.html

so I skip that part and go to the customizing I did (I only use 1 profile, the “All users” and even that contains only 1 line as you will see).

Fist watch that you have 3 options.

1) You have installed the 2015 version
2) You installed MSH for RTM
3) You Upgraded from the 2015 version

In the 1st case, you will have some set-alias lines in the “All Users” profile.msh, this are the standard aliases I recommend you keep them, in the 2nd case you will have them to after the upgrade but in this case you get a lot of errors while starting MSH this is because they are moved into the host code which gets run before the profiles do, and you can just remove them in the profile and just remove them.

I’m Monad for .NET 2.0 RTM (Upgraded, So I don’t have them, also I tried removing the standard functions and they also kept on working (so a educated guess would be the moved them to the host-code to ?) so my profile is almost empty(If you fresh installed I think it will be Empty), it only contains the following line :

. g:\MowSH\MowProfile.MSH g:\MowSH

I just call my own script from it, this makes me flexible, I want it for all users now but I could easily change this by putting the line in another profile,
The dot is for loading the script in the current scope as we want the variables to stay ;-).
I give the directory where I did put the helper scripts (as you will see later) as an argument, to Fill the $MowMSH variable, that is my "Monad Profile", but you can just do it in the profile if you want (as you see before the last upgrade was even too safe ;-) ), but I like it this way because I just put the Dir on my USB stick and I just have to copy it and add 1 line to a MSH profile of choose and I’m all tuned.
The MowSH is because it’s my Own build shell (for my own provider and CMDlets)
another way to tune MSH, but I will blog about that later :

The DirectoryStructure below the MowSH dir looks like this :

MowProfile.msh

And the following directories :

CMDLets
Functions
Lib
Providers
Tools
TypeData
Scripts
Bin

My Profile looks like this (I shortened it a bit):

$MowMsh = $args[0]

# Set Prompt

function prompt { $Dir = get-location; $host.ui.rawui.windowtitle = "/\/\o\/\/SH - $dir";Write-Host -nonewline -ForeGroundColor Red MSH;">" }

# Extra Drives

& {
get-drive | forEach {$str = "function global:$($_.name): { set-location $($_.name): } ";invoke-command $str}
Function global:var: {set-Location variable:}
Function global:fun: {set-Location function:}
}

# Load .NET Classes

[void][System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")

# Load Custom .NET Class Libraries

[void][System.Reflection.Assembly]::LoadFile("$MowMsh\Lib\MowClipBoard.dll")

# Load Custom TypeData

update-typeData "$mowmsh\TypeData\mowtypes.mshxml"

# Custom Aliases

set-alias new new-object

# ShortCut Functions (Internal)
Function cd.. {cd ..}
Function Start. {(new-object -com shell.application).Explore((pwd).tostring())}
function in-host {[system.console]::in.readtoend()}
function CopyCon{
if ($args[0] -eq $null) {[system.console]::in.readtoend() | out-file}
Else {[system.console]::in.readtoend() | out-file $args[0]}
}

# shorcut Fuctions (External)

function gwc {. $MowMsh\functions\Get-WmiClasses.msh}

# Critical Functions (External)

. $MowMsh\functions\View-Object.msh
. $MowMsh\functions\Get-WmiHelp.msh
. $MowMsh\functions\Get-WmiMethodHelp.msh
. $MowMsh\functions\More.msh

# Not Critical Functions

. $MowMsh\functions\Wipe-Screen.msh
. $MowMsh\functions\Throw-Dices.msh



I walk trough it, as most of the customizing, I did blog about before, just follow the links for more information about that item.

First the Prompt :
red MSH> prompt
Get Current dir in MSH consoleTtitle

Some Extra drives I like.
Get driveletters for All drives (Providers) in MSH
Notice the new scope here to Keep the Helpervariables out of scope,


The .Net libraries I want standard loaded
(here is the form that started this, only hidden in the OV before)

Custom DLL’s,
custom .NET libraries, this are not the CMDlets !!, as they are compiled in the custom shell (also topic for a later blog I think, the beta doc’s (see $links-section on bottom of page) also have good info on this), but this are “Normal” .NET classes I want to load, for an example see :
MSH Clipboard part 2 (of 3 ?)

Custom Typedata :
Another very strong way to tune your MSH environment !!
Update-TypeData (Democracy to the types)

Custom aliases

I don’t have much at the moment (as I would forget and post scripts with them ;-) ), but I do make a lot “on-the-fly” when working on something.

Some shortcut functions I like

CopyCon : adopted on Reskit http://www.reskit.net/monad/samplescripts.htm
The rest is self explainatory I think

Some shortcut functions to scripts I start often , as getWmiClasses.MSH.
" Wmi-Help Part 1 " Getting All the WMI Classes and Descriptions in a HashTable

But that I don’t want to load for 1 second every time I start the shell, so I don’t load the actual script Here, but I only make I shortcut GWC that call’s the script (I changed the script a bit for this, I loaded it in a new scope and made the variable global, JS advised against it, but in this case the whole point of the script is to put it Global so I did it anyway ;-) ), the script: scope is normaly better for this.

& {
$global:wmiClasses
}


Some bigger scripts I consider critical .

MSH Object Viewer : by far my most used function,
as replacement to GM,
to configure .NET objects ,
to browse WMI. (I renamed it to the view-object to be more consisted with MSH naming , but I still use it as object e.g OV(gi .) also.


" WMI help Part 2 ",Getting Help on WMI classes, ( get-WmiHelp (GWH) Function)"

WMI help Part 3 (Methods) ", Getting Help on Methods and generating Sample Scripts.
(Updated version)

To view al instances of a WMI class
WMI viewer script for MSH (GUI)

And the not critical functions I still want to keep handy,
Wipe the screen in MSH (just want to do it like this some times, mostly I need a smoke then ;-) , that’s why I can’t wait for the burn version ;-)
Thow Dices in MSH (for example to answer who gets coffee ?)

I did leave out a handful of functions I would not think you care about, also I still have a lot of usefull scripts that I just load when Needed, or still need to add as it's a bit older profile.

This blogentry got a lot bigger as I planned but I think this gave a good example if the different way’s to tune monad.

- profile
- typedata
- cmdlets
- providers

and focusing on the Profile, the different way’s to load or just alias items within a Profile.

I hope this info helps you tuning your MSH environment to your own wishes.

Gr /\/\o\/\/





posted by /\/\o\/\/
 2 comments

Tuesday, November 22, 2005

 


Einstein 2 + subtopic.



Guess someone liked both also ;-)

哈皮一下

The Original : Einstein
gr /\/\o\/\/


posted by /\/\o\/\/
 0 comments
 


Burn MSH ??



Lee Holmes has a great RawUI, script on his blog,

as you as I do, like playing with the RawUI (sentiment to sprites ?) you will like this one.

Burn-Console: A Fire-Effect Demo in MSH

to be honest I did not get it working on my box yet (only 3 lines painted).
but the example looks great.

*edit* Doink , reading the blog entry again it mentioined that this was only the first part of a series, so we have to wait a bit I guess to get it all running as in the Demo-gif ;-)

gr /\/\o\/\/

p.s. I think it's a nice one to combine with Wipe the screen in MSH so you can burn your screen clear in MSH. (and look for the reaction as some watches ;-))

(I did not find a way yet to set something like this as screensaver in MSH)


posted by /\/\o\/\/
 2 comments

Monday, November 21, 2005

 


Monad and Adam (and a preview of my to-be AD provider)



As Martin Zuguc told me that a WMI provider was show at the IT Forum by JS.

and I had looked at the PDC Provider walkthrough once again, thinking about WMI. I decided to put myself at a AD provider.

First I finally uninstalled all .NET beta stuff (I did want to do a reinstall first.. but it was keeping me to long) as MSH had messed up all my VS'es except the VS2002 , that I convinced my manager, I needed as an Admin-tool at the time ;-)
the great $50 version, made that possible. (b.t.w. I think my Euro calculator is broken as it was 100 Euro here ;-)) , but anyway cheap enough to convince my manager at the time. So you can imagine how glad I was with the VS2005 express prices ;-)

but OK, after installing a big list of beta .net stuff of my puter, downloading the C# -ISO , rebooting, I could not mount the Image, ok then I will burn it, … all my CD drives gone also, and a failing CDrom driver message in my eventlog.

After SP2 HF’s and rebooting, some google-ing… and I removed the upperfilter from the registry (just removing and redetect devices did not work), another reboot, my drives back and I could burn my image (mount proggy uninstalled in the process of Troubleshooting. )

Re-installed Monad and ready to go.

But to get back to the topic, to make an AD provider I needed an AD ….
Oops /\/\o\/\/ NO have…!
VPC beta ?.. hmm, …….(remembering a scripting guy’s article) …. Adam !

So there we go ..

Download ADAM :

http://www.microsoft.com/downloads/details.aspx?FamilyId=9688F8B9-1034-4EF6-A3E5-2A2A57B5C8E4&displaylang=en

look up the Article : (do before install, I did it later, leading to twice installing ADAM ;-)) yes, even better as I did remember, exactly what I needed !!
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnclinic/html/scripting01132004.asp

and we are ready to make are own testing AD for MSH ;-)

I made my instance mow and the DN “DC=Mow,DC=Adam” but you can mimic your own AD structure in ADAM.

I made the following script to make a start to the AD structure I needed for testing my “soon-to-be” provider.

The script looks like this :



$de = new-object system.directoryservices.directoryentry("LDAP://localhost:389/dc=mow,dc=adam")

$ou = $de.invoke("Create",("organizationalUnit", "ou=MowOu"))
$ou.invoke("setinfo")

$ou = $de.invoke("Create",("container", "cn=Users"))
$ou.invoke("setinfo")

$ou = new-object system.directoryservices.directoryentry("LDAP://localhost:389/ou=mowOu,dc=mow,dc=adam")


$user = $ou.invoke("Create",("user","cn=mow"))
$user.invoke("Put",("displayName","mow"))
$user.invoke("setinfo")


I almost exactly copied this of the article, so I would like to point you there for more information (also a group example, but all basicly the Same)


b.t.w you can't use the nice .NET 2.0 ActiveDirectoryClasses for connecting to ADAM as with a domain like I showed here : AD Infastructure exploring with MSH , to connect, but I think you can set a "default naming context" somewhere.

And now we are set, and do some testing in AD stuff in Monad without a Domain

As now I can go on to the AD-provider part it started with, I already did a part, in C# and the refactoring . help was great as I started with the template from the PDC walktrough (some more info below the sample).

so have fun with Monad and Adam ;-)

Gr. /\/\o\/\/

I got My AD provider already Partly working
The current status of my provider :



MSH H:\> new-drive ad mowadp "LDAP://localhost:389/dc=mow,dc=adam"

Name Provider Root CurrentLocation
---- -------- ---- ---------------
ad mowadp LDAP://DC=MOW,DC=ADAM

MSH H:\> cd ad:
MSH ad:\> ls

distinguishedName
-----------------
{OU=MowOu,DC=MOW,DC=ADAM}
{CN=Computers,DC=MOW,DC=ADAM}
{CN=Users,DC=MOW,DC=ADAM}

MSH ad:\> gi .


distinguishedName
-----------------
{DC=MOW,DC=ADAM}


Now I need to translate it to \mowou\users..
but I could not use the template on that because of the different structure,so I did delete all the path-helper methods from the example to clear it up a bit,(keep them on paper for reference).
Now I have to reimplement them to do my own parsing(but than again .... $regEx will do that for me lol.)also I'm just outputting the DirectoryEntry yet, I will need to wrap it also.but first needed to clean up as it was to different from the DB sample.
As I think looks nice already (if you keep the demo small enough)…
i'm just started,
But keep you posted ;-)

Second greetings /\/\o\/\/



posted by /\/\o\/\/
 7 comments

Sunday, November 20, 2005

 


Windows MineSweeper cheat



I did see a very cool C# article and code to Cheat on the windows minesweeper in :

Minesweeper, Behind the scenes
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=1104&lngWId=10


Will be a lot easier on my version ;-)
MSH Minesweeper GUI game

If you want to cheat to my version just add this

$map foreach ($.name ; $.Tag)

Before the displaying the Form ;-)

gr /\/\o\/\/

PS to make it more easy to cheat you can use the, translator function from the script ;-)

$C = $_ % $rows
$R = [math]::truncate($_/$rows)

But then again... you cant even loose in my version ;-)


posted by /\/\o\/\/
 0 comments
 


erroraction on new-item, my Wrong use of Stringbuilder



As I was in a small discussion about the use of the -errorAction Switch,
with NotBotherMeWithSpam,

I did think of a very useless and confusing use of it with new-item.

but as I think we where spaming the NG a bit already ;-),

I will post it here (below Sig).

as I type another error on my part came in on the NG,
my use of the stringbuilder class was wrong (I did use it to show where to use [VOID], but as you see below not with the stringbuilder ;-) )

you should use it like this :

$sb = $sb.append("newText")

so that would mean another edit to my script to generate "WMI method call" sample-scripts : MSH get-WmiMethodHelp (GWM) Update + format tips.

(I leave that up to you)

gr /\/\o\/\/


PS don't do this to your users !!

MSH>new-item -ea Inquire -type file testing.txt

Confirm
The file 'C:\Documents and Settings\mow\testing.txt' already exists.
[Y] Yes [A] Yes to All [H] Halt Command [S] Suspend [?] Help (default is "Y"): y
new-item : The file 'C:\Documents and Settings\mow\testing.txt' already exists.
At line:1 char:9
+ new-item <<<< -ea Inquire -type file testing.txt MSH>new-item -ea Inquire -type file testing.txt

Confirm
The file 'C:\Documents and Settings\mow\testing.txt' already exists.
[Y] Yes [A] Yes to All [H] Halt Command [S] Suspend [?] Help (default is "Y"): h
new-item : Command execution stopped because the user selected the Halt option.
At line:1 char:9
+ new-item <<<< -ea Inquire -type file testing.txt
MSH>


posted by /\/\o\/\/
 0 comments

Saturday, November 19, 2005

 


MSH Minesweeper GUI game



I after, my Thow Dices in MSH (Sttt, it originaly started as Yath, but was downgraded on the way ;-)

and ofcource after seeing the famious Alien game in MSH (I won't add another link here, but I'm sure you can find it)

I was thinking about making a simple GUI game in MSH.
(also Snake crossed my mind before, but i think i did hear of a Monad team internal version of that !?)

So I could not realy think of a simle example game, for awile.

Then today minesweeper crossed my mind as easy to make without a GUI-editor for the form.
(think did see it as a Kix-forms example before)

so I came to the script below,

It it is very basic, (even the level parameters are in the script),
I already added a Menu to make it easy to add them there, I only added the Quit Item as an example, but it would be easy to extend with a "level" and "new" option for example.

b.t.w. notice I used the New .NET MenuStrip instead of the .net 1.1 Menu-style as I used here, MSH directory watcher with popup-balloon , as it makes you more fexible in make-ing the menu . (for example add the Smily as in the original ;-)

Also you will not lose if you click a Mine, but this is also easy to add in this Block (in the Function DoClear)

if ($map[$num].tag -eq "x") {
$map[$num].text = "x"
$map[$num].BackColor = "red"
}

Enjoy,

gr /\/\o\/\/


# Mines.msh 
# very basic MineSweeper GUI game in MSH
# /\/\o\/\/ 2005 

# Level Parameters :
$rows = 16
$Cols = 16
$Mines = 40

# Build Form 

$form = new-object System.Windows.Forms.form
$Form.text = "/\/\o\/\/'s MSH Minesweeper"

# Build Menu (Only Quit now, but easy to add Level Etc.) 

$MS = new-object System.Windows.Forms.MenuStrip
$Mi = new-object System.Windows.Forms.ToolStripMenuItem("&File")

$Msi1 = new-object System.Windows.Forms.ToolStripMenuItem("&Quit")
$msi1.add_Click({$form.close()}) 
$Mi.DropDownItems.Add($msi1)

$ms.Items.Add($mi)
$form.Controls.Add($ms)

# Needed here for An Other Thread error when buttoncolection added to form.

$Button = new-object System.Windows.Forms.Button
  
$form.width = ($rows * 25) + 20
$form.Height = ($Cols * 25) + 70   

# container for buttons that make up MineField

[System.Windows.Forms.Control[]]$Map = @()

# this Function is Used by the Button click event to clear a Field

Function DoClear {
  $num = $args[0]
  $C = $num % $rows
  $R = [math]::truncate($num/$rows)
  If ($map[$num].enabled -eq $true) {
    if ($map[$num].tag -eq "x") {
       $map[$num].text = "x"
       $map[$num].BackColor = "red"
    }
    Else {
      $map[$num].BackColor = "DarkGray"
      $map[$num].FlatStyle = 'Flat'
      $map[$num].Enabled = $false
      if ($map[$num].tag -ne 0) {
        $map[$num].text = $map[$num].tag
      }
      Else {
        if ($C -gt 0) {
          doClear ($num - 1 )
          if ($R -gt 0) {
            doClear (($num - $Cols) - 1)
          }
        }
        if ($C -lt ($Cols - 1)) {
          doClear ($num + 1)
          if ($R -gt 0) {
            doClear (($num - $Cols) + 1)
          }
        }
        if ($R -gt 0) {
          doClear ($num - $cols)
        }
        if ($R -lt ($rows -1)) {
          doClear ($num + $cols)
          if ($C -gt 0) {
            doClear (($num + $Cols) - 1)
          }
          if ($C -lt ($Cols - 1)) {
            doClear (($num + $Cols) + 1)
          }
        }
      }
    }
  }
}

# Create the MineField (array of Buttons)

for ($i = 0;$i -lt $rows;$i++) 
{
  $row = @()
  for ($j = 0;$j -lt $Cols;$j++) 
  {
    $Button = new-object System.Windows.Forms.Button
    $Button.width = 25
    $Button.Height = 25
    $button.top = ($i * 25) + 25
    $button.Left = $j * 25
    $button.Name = ($i * $cols) + $j
    $Button.tag = "0"
    $button.add_click({
      [int]$num = $this.name
      $this.name
      DoClear $num 
    })

    $button.font = new-object system.drawing.font('Microsoft Sans Serif',10,'bold')
    #$Button.ForeColor
    $Row += $Button
  }
  
  $Map += $row

}

# this Function is used to update the fields surrounding mines count

Function DoRaise{
  [int]$Cell = $args[0
  if ($map[$cell].tag -ne "x"){
    $n = [int]$map[$cell].tag
    $n += 1
    $map[$cell].tag = $n
  }
}

# throw some Mines 

$Random = new-object system.random([datetime]::now.Millisecond)
for ($i = 0 ; $i -lt $Mines) {
  $num = $random.next($map.count)
  if ( $map[$num].tag -ne "x") {
    $map[$num].tag = "x"
    $C = $num % $rows
    $R = [math]::truncate($num/$rows)

    if ($C -gt 0) {
      doRaise ($num - 1)
      if ($R -gt 0) {
        doRaise (($num - $Cols) - 1)
      }
    }
    if ($C -lt ($Cols - 1)) {
      doRaise ($num + 1)
      if ($R -gt 0) {
        doRaise (($num - $Cols) + 1)
      }
    }
    if ($R -gt 0) {
      doRaise ($num - $cols)

    }
    if ($R -lt ($rows -1)) {
      doRaise ($num + $cols)
      if ($C -gt 0) {
        doRaise (($num + $Cols) - 1)
      }
      if ($C -lt ($Cols -1)) {
       doRaise (($num + $Cols) + 1)
      }
    }
     
    $i++
  }
}

# hit the Road (....ehh, the Minefield)

$form.controls.addrange($map)
$form.topmost = $true 
$form.showdialog() 




posted by /\/\o\/\/
 1 comments

Friday, November 18, 2005

 


MSH get-WmiMethodHelp (GWM) Update + format tips.



MSH get-WmiMethodHelp (GWM) function Update + format tips for the generated output.

In the 3 part series About Discovering WMI in MSH and Getting Help from WMI.

" Wmi-Help Part 1 " Getting All the WMI Classes and Descriptions in a HashTable (GetWmiClasses.MSH)

" WMI help Part 2 ",Getting Help on WMI classes, ( get-WmiHelp (GWH) Function)

" WMI help Part 3 (Methods) ", Getting Help on Methods and generating Sample Scripts.

I promised an update with better errorhandling,
, so now it looks like this :

MSH>get-WMIMethodHelp
No WMIClass given
MSH>get-WMIMethodHelp win32_share
No WMIMethod given
MSH>gwm win32_share foo
Method not found, Methods are :
Create
SetShareInfo
GetAccessMask
Delete
MSH>gwm win32_shareCreate
No WMIMethod given
MSH>gwm win32_share Create
win32_share : Create :


The Create method initiates sharing for a server resource. Only members of the Administrators or Account Operators local group or those wit
h Communication, Print, or Server operator group membership can successfully execute Create. The Print operator can add only printer queues
. The Communication operator can add only communication device queues. The method returns an integer value that can be interpretted as foll
ows:
0 - Successful completion.
2 - The user does not have access to the requested information.


..........

Much better I think ;-)

Also I added the -Computer Option to the Static Method Sample Script (it was there for the Non static but not for static),
and I added A Comment To make it more Clear what the Key Values you have to Provide are.

so the Generated script for Win32_share Delete will look like this :

# win32_share delete-Method Sample Script
# Created by Get-WmiMethodHelp
# /\/\o\/\/ 2005
# Fill InParams values before Executing
# InParams that are Remarked (#) are Optional

$Class = "win32_share"
$Method = "delete"
$Computer = "."
#win32_share Key Properties
$Name = [string]

$filter = "Name = '$Name'"
$MC = get-WMIObject $class -computer $Computer -filter $filter

$InParams = $mc.GetMethodParameters($Method)

"Calling win32_share : delete "

$R = $mc.InvokeMethod($Method,$Null)
"Result : "
$R


(As explained in the original post the $inparms line stays even if there are no imparms, but as I was looking on errorhandling this Time, I did not want to change the flow,for this

Also I got some Formatting Tips for the Help-layout, of the Help part (of all 3 scripts) I did not change the output in the script,
but will paste the formatting tips below the script so you can pick what you like ;-)

gr /\/\o\/\/


--- The Updated script : ----------

# GetWmiMethodInfo.MSH (V2)
# Gets Method Parameters with descriptions from WMI class 
# it also Creates an Example script. 
# /\/\o\/\/ 2005 

Function get-WMIMethodHelp{ 
  Param ([string] $WmiClass = "",[string] $WmiMethod = "")   

  #Check Params 

  if ($wmiClass -eq "") {"No WMIClass given";Break
  if ($wmiMethod -eq "") {"No WMIMethod given";Break

  # Set Options 

  $opt = new-object system.management.ObjectGetOptions 
  $opt.UseAmendedQualifiers = $true 

  # Connect to Class

  $MS = new-object system.management.ManagementScope 
  $mc = $false
  If ($true) {
    Trap {Continue}
    $MC = new-object system.management.ManagementClass($MS,$WMIClass,$opt) 
  }
  if ($mc -eq $false) {"WMI Class not found";Break}

  # Check if Method does Exist

  $M = $mc.Get_Methods() | foreach {$_.name}
  if ($m -ne $WMIMethod) {"Method not found, Methods are :";$m;Break}

  #make a stringBuilder to make a Template Script 

  $SB = new-Object text.stringbuilder 
  [void]$SB.Append('$Class = "') ; [void]$SB.AppendLine("$WMIClass`""
  [void]$SB.Append('$Method = "') ; [void]$SB.AppendLine("$WMIMethod`""

  # if Static Qualifier is not present then Method Needs Instance 

  $Q =  $mc.Get_Methods()[$WMIMethod].get_Qualifiers() | foreach {$_.name}
  $static = $Q -eq "Static"

  If ($static -eq $True) { 
     
    # MP is used to make it possible to choose a Computer in the generated Script   
 
    $MP = new-object system.management.ManagementPath($MS.Path.path) 

    [void]$SB.AppendLine('$MP = new-object system.management.ManagementPath'
    [void]$SB.Append('$MP.Server = "') ; [void]$SB.AppendLine("$($MP.Server)`""
    [void]$SB.Append('$MP.NamespacePath = "') ; [void]$SB.AppendLine("$($MP.NamespacePath)`""
    [void]$SB.AppendLine('$MP.ClassName = $Class`n'
    [void]$SB.AppendLine('$MC = new-object system.management.ManagementClass($MP)'

  }Else
  
    [void]$SB.AppendLine('$Computer = "."'
    [void]$SB.AppendLine("`n#$wmiClass Key Properties :"
    # IF not static We need to provide The Key Properties to get the instance. 

    $Filter = "" 
    $mc.get_Properties() | foreach { 
      $Q = $_.get_Qualifiers() | foreach {$_.name}
      $key = $Q -eq "key"
 
      If ($key -eq $True) { 
        $CIMType = $_.get_Qualifiers()["Cimtype"].Value 
        [void]$SB.AppendLine("`$$($_.Name) = [$CIMType]"
        $Filter += "$($_.name) = `'`$$($_.name)`'"  
      } 
    } 

    [void]$SB.Append('`n$filter = ');[void]$SB.AppendLine("`"$filter`""
    [void]$SB.AppendLine('$MC = get-WMIObject $class -computer $Computer -filter $filter`n'

  } 

  [void]$SB.AppendLine('$InParams = $mc.GetMethodParameters($Method)`n'

  # back to the Normal output  

  "$WMIClass : $WMIMethod :`n" 

   $q = $mc.Get_Methods()[$WMIMethod].get_Qualifiers() | foreach {$_.name}
   if ($q -eq "Description") {$mc.Get_Methods()[$WMIMethod].get_Qualifiers()["Description"].Value} 
 

  "`n$WMIMethod Parameters :" 
  # get the Parameters 
  
  $inParam = $mc.Get_Methods()[$WMIMethod].get_InParameters() 

  $HasParams = $False 
  if ($true) { 
    trap{'[None]';continue}  

    $inParam.get_Properties() | foreach { 
      $HasParams = $true 
      $Q = $_.get_Qualifiers() | foreach {$_.name}

      # if Optional Qualifier is not present then Parameter is Mandatory 
      $Optional = $q -eq "Optional"

      $CIMType = $_.get_Qualifiers()["Cimtype"].Value 
      "`nName = $($_.Name) `nType = $CIMType `nOptional = $Optional" 

      # write Parameters to Example script 

      if ($Optional -eq $TRUE) {[void]$SB.Append('# ')} 
      [void]$SB.Append('$InParams["');[void]$SB.Append("$($_.Name)`"] = ");[void]$SB.AppendLine("[$CIMType]"
      if ($q -eq "Description") {$_.get_Qualifiers()["Description"].Value} 
    } 
  } 

  # Call diferent Overload as Method has No Parameters 

  If ($HasParams -eq $True) { 
    [void]$SB.AppendLine("`n`"Calling $WMIClass : $WMIMethod with Parameters :`""
    [void]$SB.AppendLine('$inparams.get_properties() | select name,Value'
    [void]$SB.AppendLine('`n$R = $mc.InvokeMethod($Method, $inParams, $Null)'
  }Else
    [void]$SB.AppendLine("`n`"Calling $WMIClass : $WMIMethod `""
    [void]$SB.AppendLine('`n$R = $mc.InvokeMethod($Method,$Null)'
  } 

  [void]$SB.AppendLine('`"Result : `"'
  [void]$SB.AppendLine('$R'

  # Write the Sample Script : 

  "`nSample Script :`n" 
  "# $WMIclass $WMIMethod-Method Sample Script" 
  "# Created by Get-WmiMethodHelp" 
  "# /\/\o\/\/ 2005" 
  "# Fill InParams values before Executing" 
  "# InParams that are Remarked (#) are Optional`n" 

  $SB.ToString() 


set-alias gwm get-WMIMethodHelp



----- Formatting tip's for all 3 scripts :

Very nice indeed! BTW the output is a bit hard to follow because there is so much of it. I added a writeHighlightedText function which helps although is somewhat garish. :-) Note: Be sure to use only the limited set of colors found in System.ConsoleColor.

--
Keith

function writeHighlightedText {
param ([string] $text, [string] $bgColor = "DarkBlue", [string] $fgColor = "White")

$origBgColor = $host.ui.rawui.BackgroundColor
$origFgColor = $host.ui.rawui.ForegroundColor
trap [Exception] {
$host.ui.rawui.BackgroundColor = $origBgColor
$host.ui.rawui.ForegroundColor = $origFgColor
break
}

$host.ui.rawui.BackgroundColor = $bgColor
$host.ui.rawui.ForegroundColor = $fgColor
$text
$host.ui.rawui.BackgroundColor = $origBgColor
$host.ui.rawui.ForegroundColor = $origFgColor
}

writeHighlightedText "`n$WMIClass :"


The other thing you could do is:

@($MO.get_properties()) |
format-table @{label="Name";expression={$_.Name}; Width=30 }, @{Label="Description"; expression={$_.qualifiers["Description"].Value + "`n"}} -wrap

This produces a reasonable table. Jim Truher has a nice WRAP-STRING function (which wraps on word boundaries) which would make this even nice.

--
Jeffrey Snover [MSFT]

the wordwrapping script Mentioned :

James Truher [MSFT] wrote:

> This is a little word wrapping script that I often use - no magic here, but I thought you might like it.
>
>
> # a text wrapper, it takes a width and string and an indent
> param ( [int]$width = 75, [string]$string, [int]$shift = 0)
>
> $words = $string.split(" ")
> $space = " "
> $space *= $shift
> $lw = 0
> $ww = $space
> foreach($w in $words)
> {
> $lw += $w.length + 1
> if($lw -gt $width)
> {
> $ww # write the object to the result stream
> $ww = $space
> $lw = 0 + $w.length + 1
> }
> $ww += "$w "
> }
> # be sure not to leave anything else behind
> $ww

A tip from /\/\o\/\/ on this ;-)

tip, if you want to fill-up the window, use $witdh like this

$width = $host.ui.rawui.buffersize.width - $shift

or

$width = $host.ui.rawui.WindowSize.width - $shift
114

as you don't know what the users settings are.


posted by /\/\o\/\/
 0 comments
 


More on Cryptograpy and MSH



As I did say to you that I would look into it a bit more in last post :
Get-credential and Decrypting a SecureString in MSH

I got al lot of help since then (basicly they worked it all out for me), so I just post some of it here :

First I got an Example of using Encryption in MSH from Lee Holmes in the NG:


$plainText = "Meet at dawn."
$plainBytes = $(new-object System.Text.ASCIIEncoding).GetBytes($plainText)

$rijndael = new-object System.Security.Cryptography.RijndaelManaged
$rijndael.Mode = "CBC"

$saltBytes = $(new-object System.Text.ASCIIEncoding).GetBytes("Salt")
$password = new-object `
System.Security.Cryptography.PasswordDeriveBytes "PassPhrase",$saltBytes,"SHA1",2
$keyBytes = $password.GetBytes(32)

$ivBytes = $(new-object System.Text.ASCIIEncoding).GetBytes("iviviviviviviviv")
$encryptor = $rijndael.CreateEncryptor($keyBytes, $ivBytes)

$memoryStream = new-object System.IO.MemoryStream
$cryptoStream = new-object System.Security.Cryptography.CryptoStream `
$memoryStream,$encryptor,"Write"

$cryptoStream.Write($plainBytes, 0, $plainByetes.Length)
$cryptoStream.FlushFinalBlock()
$cipherTextBytes = $memoryStream.ToArray()

$memoryStream.Close()
$cryptoStream.Close()

$cipherText = [Convert]::ToBase64String($cipherTextBytes)

$cipherText


Lee Holmes [MSFT]


As this is using Rijndael not DPAPI it works with a Password.

then an example of In and exporting a Key in MSH using export-securestring, also posted by Lee Holmes in the NG :


MSH:31 C:\temp > ## Part 1: User embeds "Hello World" in a SecureString
MSH:32 C:\temp > $secureString = new-secureString
Enter secret: ***********

MSH:33 C:\temp >
MSH:33 C:\temp > ## ... and creates their secret key
MSH:34 C:\temp > $secureKey = new-secureString
Enter secret: ****************

MSH:35 C:\temp >
MSH:35 C:\temp > ## Then, they export it
MSH:36 C:\temp > $exported = export-secureString $secureString $secureKey
MSH:37 C:\temp > $exported
6f5285124d9aee83fa37c64444f30f22c0d4577f9a6c6017d8feb3fa2803c65d
MSH:38 C:\temp >
MSH:38 C:\temp > ## Part 2: Another user imports that into another SecureString, using
MSH:39 C:\temp > ## the same key.
MSH:40 C:\temp > $imported = import-secureString $exported $secureKey
MSH:41 C:\temp >
MSH:41 C:\temp > ## Then, they extract the message from the SecureString
MSH:42 C:\temp > $ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($imported)
MSH:43 C:\temp > $message = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($ptr)
MSH:46 C:\temp >
MSH:46 C:\temp > ## This is it
MSH:47 C:\temp > $message
Hello World
MSH:48 C:\temp >


I was testing this with DPAPI (Knowing it would not work, but as a test), and importing as another user, and got a strange Error (file not found), and got the second Example I promised to post as an answer ;-).

Also I got a Comment from Marcel on last post, with a nice tip about using get-credential and GetNetworkCredential to decrypt a securestring .

So thanks Marcel, for the tip,
and Lee for writing the examples for me and the rest of the Help.

gr /\/\o\/\/

PS new-securestring has no Key Option, (after I mentioned it in the NG, I got that "arrg, Ofcourse not"-feeling.) there is no use to it, so I kind of expected Lee's reaction LOL :

Lee Holmes :

I'm not sure why you'd want a key for new-secureString. If you want to use a key, the export-secureString and import-secureString (with the key parameter) should do what you want.

/\/\o\/\/:

Your right, I did think about that also (after my sleep), as the SecureString's purpose is different, it's in memory only(you need to export it anyway to get it out of your session). so only using DPAPI here makes sence ;-)


posted by /\/\o\/\/
 0 comments

Thursday, November 17, 2005

 


Get-credential and Decrypting a SecureString in MSH



In MSH there are a couple of places where you will find a SecureString.

the Most Common will be Get-Credentials.

this will give you a secure way to enter and pass credentials to a CMDlet or function.

one place in MSH where this is very handy is in get-WMIobject.
if you want to connect with alternate credentials you can pass a Credential object.
this will give you a safe way to let the user enter a password for this.





MSH>get-wmiobject -credential $(get-credential) -computer ComputerName win32_process

Cmdlet get-credential at command pipeline position 1
Supply values for the following parameters:
Credential
User: mow
Password for user mow: ***


if you look at the passwordProperty of a credentialObject, you will see that it is a secureString object.

Also some .NET classes take a SecureString as Input, as we used in the run-as function in a former post :




Function Run-as {
$cred = get-credential ; [System.Diagnostics.Process]::start($args[0],$null,$cred.UserName,$cred.password,$null)
}
there is also a bug if you do not enter credentials see :do the MSH - CMD- MSH loop. & RunAs in MSH
and if you want to load a profile with the runas look here : Runas with loading Profile script in MSH

but what if we want to use a secureString to keep are own secred string ?
making it is Simple just use new-securestring,

but if we look at the methods of the SecureString there is no decryption option.
some nice methods to play with the contents but nothing to get them out.
but keeping a Secret is not as usefull if we can not get it out again.



MSH>$secret  gm


TypeName: System.Security.SecureString

Name MemberType Definition
---- ---------- ----------
AppendChar Method System.Void AppendChar(Char c)
Clear Method System.Void Clear()
Copy Method System.Security.SecureString Copy()
Dispose Method System.Void Dispose()
Equals Method System.Boolean Equals(Object obj)
get_Length Method System.Int32 get_Length()
GetHashCode Method System.Int32 GetHashCode()
GetType Method System.Type GetType()
InsertAt Method System.Void InsertAt(Int32 index, Char c)
IsReadOnly Method System.Boolean IsReadOnly()
MakeReadOnly Method System.Void MakeReadOnly()
RemoveAt Method System.Void RemoveAt(Int32 index)
SetAt Method System.Void SetAt(Int32 index, Char c)
ToString Method System.String ToString()
Length Property System.Int32 Length {get;}


I posted this question on the NG a time ago, but did not get an answer, and concluded that then it was only usefull for the get-WMIobject Command (did not find it in some .NET classes yet at that time)

but I found the solution here :

http://msdn2.microsoft.com/library/7kt014s1(en-us,vs.80).aspx

I needed to use the System.Runtime.InteropServices.marshal class for this.

so I worked this out :



MSH>$Secret = new-SecureString
Enter secret: ************

MSH>$Secret
System.Security.SecureString
MSH>$BSTR = [System.Runtime.InteropServices.marshal]::SecureStringToBSTR($Secret)
MSH>$ClearString = [System.Runtime.InteropServices.marshal]::PtrToStringAuto($BSTR)
MSH>[System.Runtime.InteropServices.marshal]::ZeroFreeBSTR($BSTR)
MSH>$ClearString
mow's Secret
MSH>
Remarks :

And we are there so now we can use the SecureString for our Own secrets ;-)

But wait a Minute ???? ..... This is a Security Leak ... you just converted it back again ... without to enter a password or anything !!!.. what use is the SecureString then ??

The trick is that you are the only one that can do this, so if another user tries this it will not work (you can use Export-SecureString and Import-SecureString to test this)


the secureString is using Windows Data Protection.(by Default)
the API use for this is Called DPAPI. the workings are a bit complex, but the important part for the subject is that it uses the current users credentials to en/decrypt the SecureString.

For more info :

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/windataprotection-dpapi.asp
DPAPI is focused on providing data protection for users. Since it requires a password to provide protection, the logical step is for DPAPI to use a user's logon password, which it does, in a way. DPAPI actually uses the user's logon credential. In a typical system, in which the user logs on with a password, the logon credential is simply a hash of the user's password

so this is how we where able to Decrypt it and another user will not (b.t.w. it should not be possible on another Computer also !!).

combined with the import-securestring and Export-secure string this is a nice way to save personal data in MSH.
Also you can add your own key, or use Rijndael encryption if you need to be able to use only a key (I'm still a bit testing with this)

I have to look in to it still a bit more but ...
This makes the SecureString a whole lot more interesting and usefull as I did think before..

Enjoy Safely,

gr /\/\o\/\/


posted by /\/\o\/\/
 1 comments
 


Atari Laptop (no MSH content)



Now this really has nothing to-do with MSH.

This goes a bit more back,
After my first ZX-81, I got my Atari 600 (later switched to a 800),
I really loved that machine ;-)

So I'm very jealous when I look at this picture.

http://benheck.com/Games/Atari_800/Main_pic_BIG.jpg

read the WHOLE STORY or see JUST PHOTOS On http://benheck.com


Guess it's not for sale *Snif*

Gr /\/\o\/\/







posted by /\/\o\/\/
 0 comments

Tuesday, November 15, 2005

 


Sending Mail from MSH



Sending mail using SMTP in MSH is very easy.

First we Need a SMTPClient Object :


$SmtpClient = new-object system.net.mail.smtpClient


Set the SMTP-server :


$SmtpClient.host = "smtp.foo.com"


And Send a Mail :


$SMTPClient.Send("no@spam.mow","SomeOne@foo.Com","Greetings from MSH","this Greeting is Send by MSH")


The Parameters are From - To - Title - Body.

as this is not very handy we could make a script like this :


$SmtpServer = "smtp.Server.com"

$From = "no@spam.mow"
$To = "SomeOne@Foo.com"
$Title = "Greetings from MSH"
$Body = "Hello, SomeOne `n Greetings from MSH"

$SmtpClient = new-object system.net.mail.smtpClient
$SmtpClient.host = $SmtpServer


$SmtpClient.Send($from,$to,$title,$Body)


But What if we have more to Configure, like Port,Credentials and SSL ?

As you can see below you can set them all on the $SMTPclient Object


MSH>$SmtpClient


Host : smtp.Server.com
Port : 25
UseDefaultCredentials : False
Credentials :
Timeout : 100000
ServicePoint : System.Net.ServicePoint
DeliveryMethod : Network
PickupDirectoryLocation :
EnableSsl : False
ClientCertificates : {}



So we are all done now ... But then Again ... maybe not ......(C)LSL

what if we want to set a CC or add an Attachement ?, as there are no parameters for that

Let's look again at that SEND Method :



MSH>$SMTPClient.Send.OverloadDefinitions
System.Void Send(String from, String recipients, String subject, String body)
System.Void Send(MailMessage message)


It has also a Second Overload that takes a MailMessage as Input, as we have seen before in Exploring .NET types, classes and Enums from MSH this is an .NET-Class that represents a Object, on with you can fill the Properties, and then give it as argument to the Method.

I little problem here is that the overload definition only gives you the ClassName not the Path and you need that to create the Object in MSH.

a little trick for this, Just give it something and the Errormessage will tell you the compleet Path (the Number of arguments most be right for this to work)

So :


MSH>$SMTPClient.Send("Foo")
Cannot convert argument "0", with value: "Foo", for "Send" to type "System.Net.Mail.MailMessage".
At line:1 char:17
+ $SMTPClient.Send( <<<< "Foo")


... And now we know the Full Path and can Create the Object in MSH :-)


MSH>$Msg = new-object system.net.mail.MailMessage
MSH>$msg


From :
ReplyTo :
To : {}
Bcc : {}
CC : {}
Subject :
SubjectEncoding :
Headers : {mime-version}
Body :
BodyEncoding :
IsBodyHtml : False
Attachments : {}
AlternateViews : {}


As you can see you are a lot more flexible in creating your MailMessage now !

So just configure the $msg Object with the properties you want, and then send it like this :


$SmtpClient.Send($msg)

This may look a bit strange at first (if you come to MSH without OOP or a .NET background that is.) but as we also have seen here : Lets Query WMI from MSH this way of working is very powerfull and easy when you get used to it and it's very readable in you code

(try to make the script as show for the "Simple" way to send mail (without the MailMessage Object) again but now with the $MSG object, you will see how nice the code will look.

without the need to dim all that helper-variables !

also if you want to look, how the message is constructed till now or what properties there are to fill, you just type $MSH and hit the enter-key.

so you see mailing from MSH is very easy and powerfull, I'm sure you will find a good use for it ;-)

Enjoy.

gr /\/\o\/\/

P.S. and again this works very nice with the ObjectViewer (MSH Object Viewer ), try:
OV($MSG)
, than you can just configure most of the properies from the GUI and go on sending the Mail.


posted by /\/\o\/\/
 4 comments

Archives

October 2005   November 2005   December 2005   January 2006   February 2006   March 2006   April 2006   May 2006   June 2006   July 2006   August 2006   September 2006   October 2006   November 2006   December 2006  

$Links = ("PowerShell RC1 Docs"," PowerShell RC1 X86"," PowerShell RC1 X64"," Monad GettingStarted guide"," Monad Progamming Guide"," Monad SDK"," Monad videos on Channel 9"," MSH Community Workspace"," scripts.readify.net "," MonadSource"," www.reskit.net"," PowerShell Blog"," Under The Stairs"," computerperformance powershell Home"," proudlyserving"," MSH on wikipedia"," MSHWiki Channel 9"," Keith Hill's Blog"," Precision Computing"," PowerShell for fun"," MSH Memo (Japanese)"," monadblog")

find-blog -about "PowerShell","Monad" | out-Technorati.
find-blog -contains "","" | out-Technorati.
Google
 
Web mow001.blogspot.com

This page is powered by Blogger. Isn't yours?