/\/\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 "," ")

Friday, September 29, 2006

 


PowerShell RC2 and Active Directory Part 2



As Active Directory management from PowerShell is very important to me in my daily work as I do all AD, SMS and MOM management from PowerShell as well as some of the others in my department allready  ;-) , 

As you could see here : PowerShell RC2 and Active Directory  I do not like the Wapper added in RC2.

I have a lot if discussions about it ,

in the NewsGroup (Yes Finaly Google has Indexed the PowerShell NG )

AD access change/break in RC2

Syntax ([ADSI] removed by google)

getting COM properties . ([ADSI] removed by google)

ADSI - AD access changes/issues in RC2

and on IRC , there I got this remark :,

<dreeschkind> guys, you need to vote if you want to achieve anything
<dreeschkind> https://connect.microsoft.com/feedback/ViewFeedback.aspx?FeedbackID=213764&SiteID=99

  And ofcourse did add a 5 ;-)

 

In the Newsgroup Threads Aruk Kumaravel explains a bit more about the wrapper and about the methods added (hidden),

Create
Put
Set
PutEx
SetEx
GetInfo
SetInfo

and he has also some examples on his blog using the new wrapper :

http://blogs.msdn.com/arulk/archive/2006/07/25/678137.aspx

 http://blogs.msdn.com/arulk/archive/2006/07/28/682289.aspx

 http://blogs.msdn.com/arulk/archive/2006/08/24/719241.aspx

 

Most people I did hear so far that are using PoSH for AD do not like it,  and the questions on the NGm

also  ofcourse I did,some more comparing and testing  also, here you see some examples of the differences added by the wrapper :

Note that PsBase has no Tabcompletion.

 

# Old

$user.rename('cn=mow')

$root.invoke('MoveHere','LDAP://CN=mow,OU=MowOu,DC=mow,DC=local','cn=mowMoved')

# New

$user.psbase.rename('cn=mow')

$root.movehere('LDAP://CN=FooBar,DC=mow,DC=local','cn=FooMoved')

# New (not working )

([adsi]'LDAP://CN=FooMoved,DC=mow,DC=local').'AccountDisabled'
([adsi]'LDAP://CN=FooMoved,DC=mow,DC=local').get('AccountDisabled')

# Old way ( works ) :

([adsi]'LDAP://CN=FooMoved,DC=mow,DC=local').psbase.invokeget('AccountDisabled')

 

 

as you could see here  :  PowerShell and Active Directory Part 3 (UserProperties) , (last part of post) the ADSI COM Object has some added Method Properties, for a list see : Interface Property Methods. on MSDN

I do not know how to do it yet using the wrapper, (see last NG thread [ADSI]  getting COM properties . )

 

PS C:\PowerShell> ([adsi]'LDAP://CN=FooMoved,DC=mow,DC=local').'AccountDisabled'
PS C:\PowerShell> ([adsi]'LDAP://CN=FooMoved,DC=mow,DC=local').get('AccountDisabled')
Exception calling "get" with "1" argument(s): "The directory property cannot be found in the cache.
"
At line:1 char:49
+ ([adsi]'LDAP://CN=FooMoved,DC=mow,DC=local').get( <<<< 'AccountDisabled')

PS C:\PowerShell>
PS C:\PowerShell> # Old way (works):
PS C:\PowerShell>
PS C:\PowerShell> ([adsi]'LDAP://CN=FooMoved,DC=mow,DC=local').psbase.invokeget('AccountDisabled')
True

As I have almost 1500 readers of the first post of the series PowerShel and Active Directory Part 1  , and 626 that came to  PowerShell and Active Directory Part 3 (UserProperties) ,  so if you have done that start (and did read the NG threads), you have experince with the process and can give valuable feedback,   

Do you think is more easy to get started with Active Directory in PowerShell  in RC1 or RC2 ?

As that was the main goal of this change I think.

 please Vote : https://connect.microsoft.com/feedback/ViewFeedback.aspx?FeedbackID=213764&SiteID=99

or join the discussion in the microsoft.public.windows.powershell NewsGroup 

Let know what you think !,

(OK sorry one more complaint ;-) )

I still think that for this little value  that.emulating VbScript  this wrapper does add for someone starting with PowerShell (when he is coming from VbScript, and knowing all the  Methods by Head  ;-) ) ,

This wrapper does to much concessions to the usability of PowerShell  for more advanced administrator tasks, for using /converting all examples in other .NET languages (C#,IronPyhon,VB.NET,PowerShell), Developers to use PowerShell as a Tool , or to glide to a making a CmdLet , and it is very confusing, making exploring and Learning harder.

I think  the way forward, using the Framework, is the best way , see also all changes in .NET2.0 for managing AD infrastructure : /\/\o\/\/ PowerShelled: AD Infrastructure exploring with MSH  (AD is managed by admin's, not by end-users )  , as you could see in the Part 3of the series, and the example in this post, it is already easy enough to get to those Hidden Methods added by the wrapper, and we have best of both worlds. 

Also Get-Member is one of the most used and important commands in PowerShell , and in exploring Objects , and we have to be able to trust it to be consistent and complete, as it is one of our eyes into the PowerShell World. 

So I think that hiding important information from it, for some also hidden added methods is the wrong way to go on the glidepath, and I see almost nothing for it in return, as for typing PSBase.

End of campain !

 

Enjoy,

Greetings, /\/\o\/\/

Tags : Monad  PowerShell




 3 comments
 


PowerShell : Hosting IronPython



In last post about using IronPython from PowerShell : Using IronPython to Connect to AD and list children , I did just use the CLI.

In this post I will show how to Use IronPython from Powershell, by hosting it.

I first load the DLL's needed (copy them to PSHOME directory), and then just start using it.

 

[System.Reflection.Assembly]::LoadFile("$pshome\IronPython.dll")
[System.Reflection.Assembly]::LoadFile("$pshome\IronMath.dll")

$ipe = new-object IronPython.Hosting.PythonEngine 

$code = @'

import sys
import clr
import System

clr.AddReferenceByPartialName("System.DirectoryServices")

import System.DirectoryServices

from System.DirectoryServices import *

root = DirectoryEntry()

for c in root.Children: print c.Name


u = root.Children.Find("CN=FooBar")

for p in u.Properties: print p.PropertyName , p.Value

for p in u.Properties.__getitem__("CN"): print p


'@

$ipe.Execute($code)

 

 

The results are not lost you can still work with them and you can exchange variables very easy also see examples below :

 

 

# You can get back the results by using Evaluate

PS C:\PowerShell> $ipe.Evaluate('root.Children.Find("CN=FooBar")')

distinguishedName
-----------------
{CN=fooBar,DC=mow,DC=local}

# Or you can get the variable

PS C:\PowerShell> $ipe.Globals["u"]

distinguishedName
-----------------
{CN=fooBar,DC=mow,DC=local}

# Set a IronPython Variable

PS C:\PowerShell> $ipe.Globals['domain'] = [adsi]''
PS C:\PowerShell> $ipe.Evaluate('domain.Children.Find("CN=FooBar")')

distinguishedName
-----------------
{CN=fooBar,DC=mow,DC=local}

# and do a Dir (get-member) on that variable in IronPython

PS C:\PowerShell> $ipe.Evaluate('dir(domain)')
AuthenticationType
CanRaiseEvents
Children
Close
CommitChanges

 

As you see its very easy to mix  IronPython and PowerShell parts.

Realy great ! 

 

 

Enjoy,

Greetings, /\/\o\/\/

Tags : Monad IronPython PowerShell




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

Wednesday, September 27, 2006

 


PowerShell RC2 and Active Directory



As you have RC2 Installed all my AD post will not work anymore, As I did switch back on all my work PC's (I did call all my colleagues not to upgrade as all our AD tools are messed up, I will not update them, as I would not recommend to upgrade to RC2 of you work with AD a lot , as it is verry confusing, but fixable if you read explaination below,

 you can get all working again be the result might be messy.

he examples in my AD series will most of the time not work, most of the things discussed will not seem to be there , so if you did not do AD in PowerShell all seem very strange, and it will be hard to follow.

I will explain what has happened and give the ways to solve this.

As  PowerShell RC2 was released, I hopefully started to explore the new AD support  :

 

PS C:\PowerShell> [ADSI]''

distinguishedName
-----------------
{DC=mow,DC=local}

PS C:\PowerShell> $root = [ADSI]''

 

Wow Cool, but then :

 

PS C:\PowerShell> $root.get_Children()
Exception calling "get_Children" with "0" argument(s): "Unknown name. (Exception from HRESULT: 0x80020006 (DISP_E_UNKNO
WNNAME))"
At line:1 char:19
+ $root.get_Children( <<<< )

Hmm, should be there, lets remove the () :

PS C:\PowerShell> $root.get_Children

MemberType : Method
OverloadDefinitions :
TypeNameOfValue : System.Management.Automation.PSMethod
Value :
Name : get_Children
IsInstance : True

bit strange output but its there

Hmm its not there.

PS C:\PowerShell> $root | gm

TypeName: System.DirectoryServices.DirectoryEntry

Name MemberType Definition
---- ---------- ----------
auditingPolicy Property System.DirectoryServices.PropertyValueCollection auditingPolicy {get;set;}
creationTime Property System.DirectoryServices.PropertyValueCollection creationTime {get;set;}
dc Property System.DirectoryServices.PropertyValueCollection dc {get;set;}
distinguishedName Property System.DirectoryServices.PropertyValueCollection distinguishedName {get;...

...

...

Ok we do not see it but let's try PSbase

PS C:\PowerShell> $root.psbase | gm

TypeName: System.Management.Automation.PSMemberSet

Name MemberType Definition
---- ---------- ----------
add_Disposed Method System.Void add_Disposed(EventHandler value)
Close Method System.Void Close()
CommitChanges Method System.Void CommitChanges()
CopyTo Method System.DirectoryServices.DirectoryEntry CopyTo(DirectoryEntry newParent), Syste...
CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(Type requestedType)
DeleteTree Method System.Void DeleteTree()
Dispose Method System.Void Dispose()
Equals Method System.Boolean Equals(Object obj)
GetHashCode Method System.Int32 GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetType Method System.Type GetType()
get_AuthenticationType Method System.DirectoryServices.AuthenticationTypes get_AuthenticationType()
get_Children Method System.DirectoryServices.DirectoryEntries get_Children()
get_Container Method System.ComponentModel.IContainer get_Container()
get_Guid Method System.Guid get_Guid()
get_Name Method System.String get_Name()
get_NativeGuid Method System.String get_NativeGuid()
get_NativeObject Method System.Object get_NativeObject()
get_ObjectSecurity Method System.DirectoryServices.ActiveDirectorySecurity get_ObjectSecurity()
get_Options Method System.DirectoryServices.DirectoryEntryConfiguration get_Options()
get_Parent Method System.DirectoryServices.DirectoryEntry get_Parent()
get_Path Method System.String get_Path()
get_Properties Method System.DirectoryServices.PropertyCollection get_Properties()
get_SchemaClassName Method System.String get_SchemaClassName()
get_SchemaEntry Method System.DirectoryServices.DirectoryEntry get_SchemaEntry()
get_Site Method System.ComponentModel.ISite get_Site()
get_UsePropertyCache Method System.Boolean get_UsePropertyCache()
get_Username Method System.String get_Username()
InitializeLifetimeService Method System.Object InitializeLifetimeService()
Invoke Method System.Object Invoke(String methodName, Params Object[] args)
InvokeGet Method System.Object InvokeGet(String propertyName)
InvokeSet Method System.Void InvokeSet(String propertyName, Params Object[] args)
MoveTo Method System.Void MoveTo(DirectoryEntry newParent), System.Void MoveTo(DirectoryEntry...
RefreshCache Method System.Void RefreshCache(), System.Void RefreshCache(String[] propertyNames)
remove_Disposed Method System.Void remove_Disposed(EventHandler value)
Rename Method System.Void Rename(String newName)
set_AuthenticationType Method System.Void set_AuthenticationType(AuthenticationTypes value)
set_ObjectSecurity Method System.Void set_ObjectSecurity(ActiveDirectorySecurity value)
set_Password Method System.Void set_Password(String value)
set_Path Method System.Void set_Path(String value)
set_Site Method System.Void set_Site(ISite value)
set_UsePropertyCache Method System.Void set_UsePropertyCache(Boolean value)
set_Username Method System.Void set_Username(String value)
ToString Method System.String ToString()
AuthenticationType Property System.DirectoryServices.AuthenticationTypes AuthenticationType {get;set;}
Children Property System.DirectoryServices.DirectoryEntries Children {get;}
Container Property System.ComponentModel.IContainer Container {get;}
Guid Property System.Guid Guid {get;}
Name Property System.String Name {get;}
NativeGuid Property System.String NativeGuid {get;}
NativeObject Property System.Object NativeObject {get;}
ObjectSecurity Property System.DirectoryServices.ActiveDirectorySecurity ObjectSecurity {get;set;}
Options Property System.DirectoryServices.DirectoryEntryConfiguration Options {get;}
Parent Property System.DirectoryServices.DirectoryEntry Parent {get;}
Password Property System.String Password {set;}
Path Property System.String Path {get;set;}
Properties Property System.DirectoryServices.PropertyCollection Properties {get;}
SchemaClassName Property System.String SchemaClassName {get;}
SchemaEntry Property System.DirectoryServices.DirectoryEntry SchemaEntry {get;}
Site Property System.ComponentModel.ISite Site {get;set;}
UsePropertyCache Property System.Boolean UsePropertyCache {get;set;}
Username Property System.String Username {get;set;}

 

Ahh, there are all the usefull methods and properties, hmm maybe not that bad, as this works now

 

PS C:\PowerShell> $root.psBase.children

distinguishedName
-----------------
{CN=Builtin,DC=mow,DC=local}
{CN=Computers,DC=mow,DC=local}
{OU=Domain Controllers,DC=mow,DC=local}
{CN=foo,DC=mow,DC=local}
{CN=fooBar,DC=mow,DC=local}

But then again!!!!!!

First, the PSbase is hidden, so you need to be a more advanced PoSH user and know about it.

then there is no tab completion and you need this much,

 

PS C:\PowerShell> $user.InvokeGet('AccountDisabled')
Exception calling "InvokeGet" with "1" argument(s): "Unknown name. (Exception from HRESULT: 0x80020006 (DISP_E_UNKNOWNN
AME))"
At line:1 char:16
+ $user.InvokeGet( <<<< 'AccountDisabled')


PS C:\PowerShell> $user.psbase.InvokeGet('AccountDisabled')
True

PS C:\PowerShell> $user.InvokeSet('department','foo')

Exception calling "InvokeSet" with "2" argument(s): "Unknown name. (Exception from HRESULT: 0x80020006 (DISP_E_UNKNOWNN
AME))"
At line:1 char:16
+ $user.InvokeSet( <<<< 'department','foo')

Get-member does give misleading info, I think I got the BaseObject here memberset ?. 

 

PS C:\PowerShell> $user.psbase | gm

TypeName: System.Management.Automation.PSMemberSet

Name MemberType Definition
---- ---------- ----------

...

...

But after that even worse, if you follow the series you could add Properties directly and did not need to commit them (part 3) Hence you could do this :

PS C:\PowerShell> $user.displayName = 'user'

Looks OK but ... where is it ??

PS C:\PowerShell> $user.displayName
PS C:\PowerShell>

 

Refresh or commit ?

PS C:\PowerShell> $user.psbase.RefreshCache()

PS C:\PowerShell> $user.displayName

PS C:\PowerShell> $user.psbase.CommitChanges()
PS C:\PowerShell> $user | fl *

objectClass : {top, person, organizationalPerson, user}
cn : {Ken Myer}
distinguishedName : {CN=Ken Myer,DC=mow,DC=local}
instanceType : {4}
whenCreated : {8/14/2006 7:47:24 PM}
whenChanged : {9/27/2006 8:08:22 PM}
uSNCreated : {System.__ComObject}
uSNChanged : {System.__ComObject}
department : {foo}
name : {Ken Myer}
objectGUID : {147 228 120 129 152 3 234 72 153 138 249 176 59 43 99 6}
userAccountControl : {546}
badPwdCount : {0}
codePage : {0}
countryCode : {0}
badPasswordTime : {System.__ComObject}
lastLogoff : {System.__ComObject}
lastLogon : {System.__ComObject}
pwdLastSet : {System.__ComObject}
primaryGroupID : {513}
objectSid : {1 5 0 0 0 0 0 5 21 0 0 0 94 172 186 232 167 29 117 70 12 60 36 84 68 13 0 0}
accountExpires : {System.__ComObject}
logonCount : {0}
sAMAccountName : {$4A3000-FT61QRM67UFO}
sAMAccountType : {805306368}
objectCategory : {CN=Person,CN=Schema,CN=Configuration,DC=mow,DC=local}
nTSecurityDescriptor : {System.__ComObject}

PS C:\PowerShell> $user.psbase.displayName = 'user'
Property 'displayName' cannot be found on this object; make sure it exists and is settable.
At line:1 char:14
+ $user.psbase.d <<<< isplayName = 'user'

Hmm, let go the hard way then (and again the Psbase !!!!)

PS C:\PowerShell> $user.psbase.InvokeSet('displayname','foo')
PS C:\PowerShell> $user.psbase.CommitChanges()
PS C:\PowerShell> $user | fl *

objectClass : {top, person, organizationalPerson, user}
cn : {Ken Myer}
distinguishedName : {CN=Ken Myer,DC=mow,DC=local}
instanceType : {4}
whenCreated : {8/14/2006 7:47:24 PM}
whenChanged : {9/27/2006 8:13:11 PM}
displayName : {foo}
...

...

And now it works, but you see that we seem to be back in the ADAM limits !!!,

also this is ofcourse very dangerous, as it does only work sometimes.

PS C:\PowerShell>
PS C:\PowerShell> $user.displayname = 'bar'
PS C:\PowerShell> $user

distinguishedName
-----------------
{CN=Ken Myer,DC=mow,DC=local}

PS C:\PowerShell> $user.displayname
bar

 

So you see this makes working with AD interactive very errorprone, and lots of extra troubles and gotyas to take care of, and I hope that this will be solved for RTM as I think this makes PowerShell AD support much worse opposed to better,and lots of boilercode making scripts harder to read.

I realy wonder how they came to this and if they did eat there own dogfood on this one, as I can not get what they see as improvements for this wrapper.

for WMI the ++ are mutch greater (direct method access)  as the -- (losing getInstances() e.g.)

 but for AD please give me only the [ADSI] shortcut, and remove that wrapper again, as said and shown I think this makes it even harder for starters in PowerShell to explore AD.

 

So as you could see in last post I got started with IronPython for AD management also, it is a lot more clear as current solution in RC2, as dir() does show all directly , but as PTY is limited (no tabcompletion) but we have dir() next to the PTY examples (as we have no tabcompletion and PowerShell commands(direct see PowerShell Memo links) in next post I also will work out loading the IronPython DLL to work with it from PowerShell and embed it inside a script using a here string in and add some more AD stuff, also I look into the Event Form and Thread support in IronPython and how to borrow this functionality from IronPython to extend PowerShell.

Our Japanese MVP newpops is also doing a series on doing it the other way around hosting PowerShell in IronPython PowerShell Memo:

be sure to take a look, only the code samples impressive enough and will get you going or you can use Google to translate.

[PowerShell][IronPython]PowerShell from IronPython

[PowerShell][IronPython]PowerShell from IronPython Part 2

Very Very cool also, so when we take best of all "Dynamic" worlds all will be good and PoSHy ;-)

 

Enjoy,

Greetings, /\/\o\/\/

Tags : Monad IronPython PowerShell




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

Tuesday, September 26, 2006

 


PowerShell : Using IronPython to Connect to AD and list children



  1. Iron Python is Released,

IronPython Release 1 P.0 Production

 

so here is an Hint  example how to start the IronPython CLI (ipy.exe) from powershell and to connect to the Active Directory RootDSE and to list its children.

PS C:\PowerShell> C:\IronPython-1.0\ipy.exe
IronPython 1.0.60816 on .NET 2.0.50727.42
Copyright (c) Microsoft Corporation. All rights reserved.
>>> import sys
>>> import clr
>>> import System
>>>
>>> clr.AddReferenceByPartialName("System.DirectoryServices")
>>> root = System.DirectoryServices.DirectoryEntry()
>>> for c in root.Children: print c.Name
...
CN=Builtin
CN=Computers
OU=Domain Controllers
CN=foo
CN=ForeignSecurityPrincipals
CN=Infrastructure
CN=Ken Myer
CN=LostAndFound
OU=MowOtherOU
OU=MowOu
CN=NewUs:::er0003
CN=NewUser0010
CN=NewUser0011
CN=NewUser0012
CN=NTDS Quotas
CN=Program Data
CN=System
CN=Users
>>> exit
'Use Ctrl-Z plus Return to exit'
>>> ^Z

*Edit* Importing NameSpaces, Cool !, but do not throw $$ around ;-)

 

import System.DirectoryServices
from System.DirectoryServices import *

root = DirectoryEntry()

>>> u = root.Children.Add("CN=fooBar","User")
>>> $u.name
Traceback (most recent call last):
SyntaxError: unexpected token bad character '$' (<stdin>, line 1)


>>> u.Name
'CN=fooBar'

Enjoy,

Greetings, /\/\o\/\/

Tags : Monad IronPython PowerShell




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

Monday, September 18, 2006

 


PowerShell Session video of Bruce Payette



 

From Loren Bandiera’s weblog I found the Lang.NET Symposium page

with on that :.

 

  • Bruce Payette - Discussing the new Windows PowerShell. Huge improvement over cmd.exe
  •  

    I'm watching en enjoying it at the moment,

     

    Recomended !!

     

    Enjoy,

    Greetings, /\/\o\/\/
    Tags : Monad msh PowerShell




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

    Tuesday, September 12, 2006

     


    PowerShell : Active Directory Part 11 - moving - Renaming Objects



    In this post Move and Renaming AD objects,

    still not about Searching AD as I did say before using the DirectorySearcher Object,

     but as a lot of my older posts and examples about  already use it, If you did read the read the other parts of this AD series, you should be able understand those example scripts to get much information from that older scripts about searching AD going on from the examples, and pasting in lines of code from the examples into the interactive Shell .  

    See for a complete list, of all the parts in this series, and the other examples and scripts using the DirectorySearcher. 

    The excellent PowerShell Links directory Dance2Die maintains on Del.icio.us : PowerShell (Note the RSS feed !! )in the Active Directory Subdirectory: del.icio.us PowerShell AD links

    (if can you make a get-Aduser ($SamAccountName){} from that using a DirectorySearcher as an example, please leave it in the comments ;-) 

    so in this post renaming and moving objects as that was not discussed yet :

     

    Yesterday night,  I got a question on how to rename a user in PoSH on IRC (IRC.freeNode.net #PowerShell).

    I could not come up with a direct answer at the time, but did remember from VbScript that you could use a method on the OU, 

    I did a quick lookup, Microsoft Windows 2000 Scripting Guide - Moving and Renaming User ...

    and came to this :

    PoSH>$MowOu = C:\PowerShell\ActiveDirectoryBrowser.Ps1

    PoSH>$mowOU

    distinguishedName
    -----------------
    {OU=MowOu,DC=mow,DC=local}

    PoSH>$mowou.get_Children()

    distinguishedName
    -----------------
    {CN=$_,OU=MowOu,DC=mow,DC=local}
    {CN=foo,OU=MowOu,DC=mow,DC=local}
    {CN=foobar,OU=MowOu,DC=mow,DC=local}
    {CN=Ken Myer,OU=MowOu,DC=mow,DC=local}
    {CN=mow,OU=MowOu,DC=mow,DC=local}
    {CN=Mow2,OU=MowOu,DC=mow,DC=local}
    {OU=MowSubOu,OU=MowOu,DC=mow,DC=local}
    {CN=NewUser0003,OU=MowOu,DC=mow,DC=local}
    {CN=NewUser0010,OU=MowOu,DC=mow,DC=local}
    {CN=NewUser0011,OU=MowOu,DC=mow,DC=local}
    {CN=NewUser0267,OU=MowOu,DC=mow,DC=local}
    {CN=TestGroup,OU=MowOu,DC=mow,DC=local}

    PoSH>$mowOU.invoke('MoveHere','LDAP://CN=mow,OU=MowOu,DC=mow,DC=local','cn=mowMoved')

    distinguishedName
    -----------------
    {CN=mowMoved,OU=MowOu,DC=mow,DC=local}

     

    After I came home from work today and found back the PowerShell console as I left it last night,

    I did a get-member again, and did see that I had missed the most obvious solution last night, using the Methods on the DirectoryObject.

    PoSH>$mowOU | gm -MemberType method

    TypeName: System.DirectoryServices.DirectoryEntry

    Name MemberType Definition
    ---- ---------- ----------
    add_Disposed Method System.Void add_Disposed(EventHandler value)
    Close Method System.Void Close()
    CommitChanges Method System.Void CommitChanges()
    CopyTo Method System.DirectoryServices.DirectoryEntry CopyTo(DirectoryEntry newParent), Syste...
    CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(Type requestedType)
    DeleteTree Method System.Void DeleteTree()
    Dispose Method System.Void Dispose()
    Equals Method System.Boolean Equals(Object obj)
    get_AuthenticationType Method System.DirectoryServices.AuthenticationTypes get_AuthenticationType()
    get_Children Method System.DirectoryServices.DirectoryEntries get_Children()
    get_Container Method System.ComponentModel.IContainer get_Container()
    get_Guid Method System.Guid get_Guid()
    get_Name Method System.String get_Name()
    get_NativeGuid Method System.String get_NativeGuid()
    get_NativeObject Method System.Object get_NativeObject()
    get_ObjectSecurity Method System.DirectoryServices.ActiveDirectorySecurity get_ObjectSecurity()
    get_Options Method System.DirectoryServices.DirectoryEntryConfiguration get_Options()
    get_Parent Method System.DirectoryServices.DirectoryEntry get_Parent()
    get_Path Method System.String get_Path()
    get_Properties Method System.DirectoryServices.PropertyCollection get_Properties()
    get_SchemaClassName Method System.String get_SchemaClassName()
    get_SchemaEntry Method System.DirectoryServices.DirectoryEntry get_SchemaEntry()
    get_Site Method System.ComponentModel.ISite get_Site()
    get_UsePropertyCache Method System.Boolean get_UsePropertyCache()
    get_Username Method System.String get_Username()
    GetHashCode Method System.Int32 GetHashCode()
    GetLifetimeService Method System.Object GetLifetimeService()
    GetType Method System.Type GetType()
    InitializeLifetimeService Method System.Object InitializeLifetimeService()
    Invoke Method System.Object Invoke(String methodName, Params Object[] args)
    InvokeGet Method System.Object InvokeGet(String propertyName)
    InvokeSet Method System.Void InvokeSet(String propertyName, Params Object[] args)
    MoveTo Method System.Void MoveTo(DirectoryEntry newParent), System.Void MoveTo(DirectoryEntry...
    RefreshCache Method System.Void RefreshCache(), System.Void RefreshCache(String[] propertyNames)
    remove_Disposed Method System.Void remove_Disposed(EventHandler value)
    Rename Method System.Void Rename(String newName)
    set_AuthenticationType Method System.Void set_AuthenticationType(AuthenticationTypes value)
    set_ObjectSecurity Method System.Void set_ObjectSecurity(ActiveDirectorySecurity value)
    set_Password Method System.Void set_Password(String value)
    set_Path Method System.Void set_Path(String value)
    set_Site Method System.Void set_Site(ISite value)
    set_UsePropertyCache Method System.Void set_UsePropertyCache(Boolean value)
    set_Username Method System.Void set_Username(String value)
    ToString Method System.String ToString()

    So you also can do this :

    # Using the DirectoryEntry Rename method

    PoSH>$mowOU.get_Children() |? {$_.cn -match 'mowMoved'}

    distinguishedName
    -----------------
    {CN=mowMoved,OU=MowOu,DC=mow,DC=local}

    PoSH>$MowMoved = $mowOU.get_Children() |? {$_.cn -match 'mowm'}

    PoSH>$MowMoved

    distinguishedName
    -----------------
    {CN=mowMoved,OU=MowOu,DC=mow,DC=local}

    PoSH>$MowMoved.rename('cn=mow')
    PoSH>$MowMoved

    distinguishedName
    -----------------
    {CN=mow,OU=MowOu,DC=mow,DC=local}

     

    # Connect to RootDSE and go to user by setting a new path using Set_Path

    PoSH>$mow = new-object system.directoryservices.directoryEntry
    PoSH>$mow

    distinguishedName
    -----------------
    {DC=mow,DC=local}

    PoSH>$mow.set_path('LDAP://CN=mow,OU=MowOu,DC=mow,DC=local')
    PoSH>$mow

    distinguishedName
    -----------------
    {CN=mow,OU=MowOu,DC=mow,DC=local}

    You can see from this that it is handy that you can use the methods you are used to (or vaguely remember) from VbScript.

    And you can use the methods from the .NET Wrapper Object ( you can learn about using Get-Member ).

    Ok, Ok the CmdLets are for V2, (but I did hear some rumors about some extra functionality for AD as well as for WMI in RC2 .),

    but working in the Interactive Shell console like this trying things interactively , combining Old and discovered knowledge, having much less looking up of Information and templates for admin task, using SDK DLL's (MOM 2005,SMS2003)gives you that kind of a productivity boost compared to working in VbScript ( a guess for me it's 10x and sometimes (for on the fly work ) much more (could be days ), as against doing the same in VbScript, and 2 or 3 times for CMD.EXE and commandline tool usage where applicable )

    That sometimes I really feel like flying in PowerShell ;-) 

    and we can make our own functions with ease from the commands also :

     

    PoSH>function get-ADObject ($Path) {new-object system.directoryservices.directoryEntry($path)}
    PoSH>get-ADObject 'LDAP://CN=mow,OU=MowOu,DC=mow,DC=local'

    distinguishedName
    -----------------
    {CN=mow,OU=MowOu,DC=mow,DC=local}

     

     and with the easy of making GUI Forms in PowerShell see  PowerShell : Active Directory Part 10 (AD Browser) , for exporing the AD tree and visual selecting an AD object for use in PowerShell, that also makes it easy to get to AD objects for interactive tasks.

    Not everything is perfect yet (Exception Handling, for in scripts,Remoting etc.), but I would  not be able to live without it for my dayly work allready.

    If you followed this series, and  / or used PowerShell for AD management, compared to how you used to do you think it gives you a productivity boost, or will be able to ? I would be glad to hear what you think about this , please leave a comment about that also (Ok, enough begging, but my read / comment rate is low ;-) )

    Enjoy,

    Greetings, /\/\o\/\/

    Tags : Monad msh PowerShell


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

    Thursday, September 07, 2006

     


    PowerShell : Learn about the HashTable Object and other Collections



    In the TechNet ScriptCenter there is a series : Sesame Script  If you’re new to scripting, these articles will teach you the basics and help get you started.

    (Check out also the  Sesame Script Archives , although the Series is aimed at beginners also some more advanced topics get explained, an all articles are a good read.), also the concepts are often also usable in PowerShell so even they are in VbScript they still can be a good resource for learning PowerShell) 

    In this part of the series : Sesame Script: The Dictionary Object , a Dictionary Object is discussed

    In PowerShell we have a similar object called a HashTable that works almost the same and other .NET Collection Classes we can use that work like this, so this concepts are also good to know mastering PowerShell, the WMI example might not be the best example as it is an collection of objects already, but as an ArrayList is used also in for example a Select statement for more info also PowerShell and Active Directory Part 5 so is good to understand, and if you did not get the use in the Select completely its also good to get this background.

    the HashTable unlike many other things do not enumerate on the pipeline. this can be a catch Wmi-Help Part 1

    In this post I will follow the Sesame Script Article with similar command in PowerShell and point out the PowerShell Specifics, be sure to read the part in the "Sesame Script" article completely first.

     

    An Example that Doesn’t Use the HashTable Object

     

    PoSH>gwmi win32_service | fl name,state

    name : Alerter
    state : Stopped

    name : Eventlog
    state : Running

    The next example about Filtering

     

    PoSH>gwmi win32_service -filter "state = 'Stopped'" | ft name,state

    name state
    ---- -----
    Alerter Stopped
    ALG Stopped

    An Example that Does Use the Dictionary Object

     

    PoSH>gwmi win32_service |% {$ht = @{}}{$ht.add($_.name,$_.state)}
    PoSH>$ht

    Name Value
    ---- -----
    Eventlog Running
    Alerter Stopped

    First note we can create a HashTable like this in PowerShell

     

    PoSH>@{} | gm

    TypeName: System.Collections.Hashtable

    Name MemberType Definition
    ---- ---------- ----------
    Add Method System.Void Add(Object key, Object value)
    Clear Method System.Void Clear()

    PoSH>@{name = 'mow'}

    Name Value
    ---- -----
    name mow

     

    PoSH>@{'name' = 'mow'; 'shell' = 'PoSH'}

    Name Value
    ---- -----
    name mow
    shell PoSH

    Listing the Names of Stopped Services

     

    PoSH>$ht.keys |? {$ht."$_" -eq 'Stopped'}
    Alerter
    ALG

    Running :

     

    PoSH>$ht.keys |? {$ht.Item($_) -eq 'Running'}
    Eventlog
    W32Time

    Other Things You Should Know About the Dictionary Object

     

    PoSH>$ht.Contains('Alerter')
    True
    PoSH>$ht.Contains('foo')
    False

    PoSH>$ht.ContainsValue('Running')
    True
    PoSH>$ht.ContainsValue('Alerter')
    False

    For the rest see the Get-Member output

    you can get to the DictionaryEntries it contains by calling the GetEnumerator yourself :


    PoSH>$ht.GetEnumerator()

    Name Value
    ---- -----
    Eventlog Running
    Alerter Stopped

     

    PoSH>$ht.GetEnumerator() | gm

    TypeName: System.Collections.DictionaryEntry

    Name MemberType Definition
    ---- ---------- ----------
    Name AliasProperty Name = Key
    Equals Method System.Boolean Equals(Object obj)
    get_Key Method System.Object get_Key()
    get_Value Method System.Object get_Value()
    GetHashCode Method System.Int32 GetHashCode()
    GetType Method System.Type GetType()
    set_Key Method System.Void set_Key(Object value)
    set_Value Method System.Void set_Value(Object value)
    ToString Method System.String ToString()
    Key Property System.Object Key {get;set;}
    Value Property System.Object Value {get;set;}

    You can also see more advanced examples of working with the HashTable Object in an MSH post (nothing changed here) here :

    : Get AD info into a nested HashTable from MSH , (also a good read if you follow the AD series, as this also contains info about how to construct the Query for a Search of Active DIrectory using a directory Searcher)

    Also use get-Member well  ( Strange behavour of get-member on DataTables  ), and Check out the Other collection members :

    Other Usefull Collections

     

    PoSH>$h = new Collections.Hashtable
    PoSH>$h | gm

    TypeName: System.Collections.Hashtable

    PoSH>[System.Collections.ArrayList](1,2)
    1
    2

    PoSH>,[System.Collections.ArrayList](1,2) | gm

    TypeName: System.Collections.ArrayList

    PoSH>$s = [System.Collections.Stack]('a','b')
    PoSH>$s.count
    2
    PoSH>$s.pop()
    b
    PoSH>$s.count
    1
    PoSH>,$s | gm

    TypeName: System.Collections.Stack

     

    PoSH>$sl = new System.Collections.SortedList
    PoSH>Get-Member -InputObject $sl

    TypeName: System.Collections.SortedList

     

    PoSH>$q = [System.Collections.Queue]('a','b')

    PoSH>$q.Dequeue()
    a
    PoSH>,$q | gm

    TypeName: System.Collections.Queue

     You see that this basic collection logic and get-member, can get a whole lot of possibilities next to a simple array to store Objects.

    and you can use get-member-inputObject to list the methods of the Collection.

     

    Greetings, /\/\o\/\/

    Tags : Monad msh PowerShell




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

    Wednesday, September 06, 2006

     


    PowerShell : Setting SendAs permission in Exchange 2003 (AD)



    On the "You had me at EHLO" Exchange Team blog, you can find this excelent Post with PowerShell Examples for E12.

     Exchange Server 2007 recipient management one-liners

    But not all is lost if you still Have Exchange 2003 as much of the tasks listed here, you can also do in Active Directory directly.

    I will show here also how you can do this directly in AD using PowerShell, for as you have an Exchange 2003 environment and you need to do this, and so you can see the difference with and without the Exchange 2007 Cmdlet, 

    I select the mailbox from AD with the PowerShell Active Directory Browser from Last post in the AD series PowerShell : Active Directory Part 10 (AD Browser)  , ofcourse there are other ways to get at the mailbox as you could see in that series: 

    # Grant "Send-As" permission E12

    Add-ADPermission testmbx -ExtendedRights Send-As -user jaredz

    # Using AD Browser to get to mailbox

    $mailbox = Browse-ActiveDirectory
    $AccountName = 'Mow'

    # Grant "Send-As" Permission Exchange 2003 (ActiveDirectory)

    $acl = new-object System.DirectoryServices.ActiveDirectoryAccessRule ([Security.Principal.NTAccount]$AccountName,'ExtendedRight','Allow','ab721a54-1e2f-11d0-9819-00aa0040529b'
    $Mailbox.get_ObjectSecurity().AddAccessRule($acl)
    $mailbox.CommitChanges() 

     For some more info about setting Active Directory  ACL's and ExtendedRights see also PowerShell and Active Directory Part 8 (ACL's) , or do a Search for the GUID : 'ab721a54-1e2f-11d0-9819-00aa0040529b'  in Google for more info about SendAs and Exchange 2003 (SP1 + ).

    Enjoy,

    greetings /\/\o\/\/
    Tags : Monad msh PowerShell




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

    Tuesday, September 05, 2006

     


    PowerShell : Active Directory Part 10 (AD Browser)



    For this part 10 of this series, I'v made a GUI Active Directory Browser script in PowerShell.



    *Warning* As you have RC2 Installed all my AD posts will not work anymore, it is verry confusing, but fixable if you read explaination here PowerShell RC2 and Active Directory :


    As I did switch back on all my work PC's (I did call all my colleagues not to upgrade as all our AD tools are messed up, I will not update them, as I would not recommend to upgrade to RC2 of you work with AD a lot.


    *Edit 2* an RC2 version of this script you can find in the Comments, updated by Jakke, Thanks Jakke !

    In the first post in this Active Directory series, PowerShell and Active Directory Part 1 , I showed how you could connect to the root of an Active Directory Domain,


    $root = New-Object System.DirectoryServices.DirectoryEntry


    Get a Sub OU :


    $mowOU = $root.get_Children().find('ou=mowOu')


    Connect directly to an Active Directory Object : 


    $mowOu = New-Object DirectoryServices.DirectoryEntry(LDAP://OU=MowOu,DC=mow,DC=local)


    And how to use them on the CommandLine,


    From there on, we amongst others,


    Listed and created AD Objects, as OU's Users and Groups, Changed properties, Used methods, Exported and Imported/Created the Objects (Users) to and from a CSV file and did set ACL's to AD Objects.


    But if you need to connect to a SubOU deep in the AD tree, it is hard to get at it this way, we or need a lot of Get_Children() and Find() Methods, or a long LDAP path.


    In next post we will so how to search for Objects in Active Directory using a DirectorySearcher, and how you can connect to the Active Directory Object from the results,that also will solve part of this problem.


    But most of the times  would also be handy to be be able to just browse through the AD Tree to the Object you need and then use it in PowerShell to perform some actions.


    I Made a Script for this in PowerShell  : BrowseActiveDirectory.ps1


    This Script will connect to the Root of the Domain or to custom root (a Subcontainer supplied as a DirectoryEntry Object, if you did follow the rest of the series, I hope this makes perfect sense ;-) ) and if this succeeds builds a Form that contains a TreeView Object, that you can use to browse to the AD object you  need, and then Returns it so you can use it in PowerShell.


    This Form, (as you might have seen in my Teaser), Looks like this (click picture to enlarge)



    In this case I walked to the OU : MowOU, I also used in former examples, when the Active Directory Browser will Startup you will only see the Root Object with the DN of the AD Object it represents.


    for performance reasons, not the Whole AD-tree will be read when starting up, but only when you select a Node in the TreeView, the Children of the AD object it presents get enumerated and there DN's are added to the TreeView, we will use events from the TreeView to do this.


    When you use the Select Button or hit Enter, the DirectoryEntry will be retrieved and Passed back to the pipeline so  you can Catch it in the PowerShell console and put it into a variable for further use.


    I like this GUI form as a quick way to get to the Object I want in AD, it is much quicker then getting there from the commandline, or it also much easier to explore and look at the structure of the ActiveDirectory domain this way. 


    As already mentioned in  PowerShell and Active Directory Part 8 (ACL's) , I like to just use "loose lines of Code" or functions, that you just can just past into the Commandline, so most of my examples are given that way


    And I gave some more examples and explained a bit more about the difference with Scripts here :PowerShell, Has my Dell a dangerous battery ? ,


    This script I made Hybrid, you can start it directly or start it to load the function, I did add this function as a Switch Parameter,


    so Next to Using the script Directly like this :


     



    PoSH>$De = .\ActiveDirectoryBrowser.Ps1
    PoSH>$De = fl *
    PoSH>$De = .\ActiveDirectoryBrowser.Ps1
    PoSH>$De | fl *

    objectClass : {top, organizationalUnit}
    ou : {MowSubOu}
    distinguishedName : {OU=MowSubOu,OU=MowOu,DC=mow,DC=local}
    instanceType : {4}
    whenCreated : {6/26/2006 6:59:59 PM}
    whenChanged : {6/26/2006 6:59:59 PM}
    uSNCreated : {System.__ComObject}
    uSNChanged : {System.__ComObject}
    name : {MowSubOu}
    objectGUID : {162 13 61 122 139 39 201 72 161 216 129 101 53 217 180 114}
    objectCategory : {CN=Organizational-Unit,CN=Schema,CN=Configuration,DC=mow,DC=local}
    nTSecurityDescriptor : {System.__ComObject}

    # Use this as new Root


    PoSH>.\ActiveDirectoryBrowser.Ps1 $de


    You can also use the Browse-ActiveDirectory Function that does all the work in the Script, by  Loading it into your current session by dotSourcing the ActiveDirectoryBrowser.Ps1 script and providing the -loadOnly Switch


    then you can use the Browse-ActiveDirectory function interactively from then on, so you can also use this script in your profile



    If you use the -LoadOnly Switch but do not DotSource it the script will warn you like this :


     



    PoSH>.\ActiveDirectoryBrowser.Ps1 -l
    WARNING: LoadOnly Switch is given but you also need to 'dotsource' the script to load the function in the global scope
    To Start a script in the global scope (DotSource) put a dot and a space in front of path to the script
    If the script is in the current directory this would look like this :
    . .\ActiveDirectoryBrowser.Ps1
    then :
    The Browse-ActiveDirectory Function is loaded and can be used like this :
    $de = Browse-ActiveDirectory

    PoSH>. .\ActiveDirectoryBrowser.Ps1 -l
    The Browse-ActiveDirectory Function is loaded and can be used like this :
    $de = Browse-ActiveDirectory


    If you use the script this way for loading the function, it also will Define the alias Bad for ease of use 


    I hope this LoadOnly option example also shows a bit how you can use the different forms of starting things in PowerShell.


    The Script looks like this :


     


     


    # ActiveDirectoryBrowser.Ps1
    #
    # This script does show a GUI to browse ActiveDirectory in a Treeview
    # and Returns the DirectoryEntry Selected for use in PowerShell
    # or if LoadOnly Parameter is given it just loads the Browse-ActiveDirectory function, 
    # and does set the alias bad, for loading the function for interactive use by dotsourcing the script
    #
    # /\/\o\/\/ 2006
    #
    # http://mow001.blogspot.com

    param (
      [directoryservices.directoryEntry]$root = (new-object system.directoryservices.directoryEntry),
      [Switch]$LoadOnly
    )

    # the Main function that can be loaded or gets started at the end of the script
     
    Function Browse-ActiveDirectory {
      param ([directoryservices.directoryEntry]$root = (new-object system.directoryservices.directoryEntry))

      # Try to connect to the Domain root

      &{trap {throw "$($_)"};[void]$Root.get_Name()}

      # Make the form

      $form = new-object Windows.Forms.form   
      $form.Size = new-object System.Drawing.Size @(800,600)   
      $form.text = "/\/\o\/\/'s PowerShell ActiveDirectory Browser"  

      # Make TreeView to hold the Domain Tree

      $TV = new-object windows.forms.TreeView
      $TV.Location = new-object System.Drawing.Size(10,30)  
      $TV.size = new-object System.Drawing.Size(770,470)  
      $TV.Anchor = "top, left, right"    

      # Add the Button to close the form and return the selected DirectoryEntry
     
      $btnSelect = new-object System.Windows.Forms.Button 
      $btnSelect.text = "Select"
      $btnSelect.Location = new-object System.Drawing.Size(710,510)  
      $btnSelect.size = new-object System.Drawing.Size(70,30)  
      $btnSelect.Anchor = "Bottom, right"  

      # If Select button pressed set return value to Selected DirectoryEntry and close form

      $btnSelect.add_Click({
        $script:Return = new-object system.directoryservices.directoryEntry("LDAP://$($TV.SelectedNode.text)"
        $form.close()
      })

      # Add Cancel button 

      $btnCancel = new-object System.Windows.Forms.Button 
      $btnCancel.text = "Cancel"
      $btnCancel.Location = new-object System.Drawing.Size(630,510)  
      $btnCancel.size = new-object System.Drawing.Size(70,30)  
      $btnCancel.Anchor = "Bottom, right"  

      # If cancel button is clicked set returnvalue to $False and close form

      $btnCancel.add_Click({$script:Return = $false ; $form.close()})

      # Create a TreeNode for the domain root found

      $TNRoot = new-object System.Windows.Forms.TreeNode("Root")
      $TNRoot.Name = $root.name
      $TNRoot.Text = $root.distinguishedName
      $TNRoot.tag = "NotEnumerated"

      # First time a Node is Selected, enumerate the Children of the selected DirectoryEntry

      $TV.add_AfterSelect({
        if ($this.SelectedNode.tag -eq "NotEnumerated") {

          $de = new-object system.directoryservices.directoryEntry("LDAP://$($this.SelectedNode.text)")

          # Add all Children found as Sub Nodes to the selected TreeNode

          $de.get_Children() | 
          foreach {
            $TN = new-object System.Windows.Forms.TreeNode
            $TN.Name = $_.name
            $TN.Text = $_.distinguishedName
            $TN.tag = "NotEnumerated"
            $this.SelectedNode.Nodes.Add($TN)
          }

          # Set tag to show this node is already enumerated
     
          $this.SelectedNode.tag = "Enumerated"
        }
      })

      # Add the RootNode to the Treeview

      [void]$TV.Nodes.Add($TNRoot)

      # Add the Controls to the Form
      
      $form.Controls.Add($TV)
      $form.Controls.Add($btnSelect ) 
      $form.Controls.Add($btnCancel )

      # Set the Select Button as the Default
     
      $form.AcceptButton =  $btnSelect
         
      $Form.Add_Shown({$form.Activate()})   
      [void]$form.showdialog() 

      # Return selected DirectoryEntry or $false as Cancel Button is Used
      Return $script:Return
    }

    # If used as a script start the function

    Set-PSDebug -Strict:$false #  Otherwise Checking the Switch parmeter does fail (Bug ?)

    if ($LoadOnly.IsPresent) {

      # Only load the Function for interactive use

      if (-not $MyInvocation.line.StartsWith('. ')) {
        Write-Warning "LoadOnly Switch is given but you also need to 'dotsource' the script to load the function in the global scope"
        Write-Host "To Start a script in the global scope (dotsource) put a dot and a space in front of path to the script"
        Write-Host "If the script is in the current directory this would look like this :"
        Write-Host ". .\ActiveDirectoryBrowser.Ps1"
        Write-Host "then :"
      }
      Write-Host "The Browse-ActiveDirectory Function is loaded and can be used like this :"
      Write-Host '$de = Browse-ActiveDirectory'
      Set-alias bad Browse-ActiveDirectory
    }
    Else {

      # start Function

      . Browse-ActiveDirectory $root

    }

     


     


    Most of this Code is straight forward I think with the # comments( if you followed the AD series, and have seen some of my other PowerShell GUI Examples) , just remember that the add_* methods are used to add scripts to events from the objects on the Form.


    here some remark by the main points of interest in the script (sorry Numbers Gone) :


    Line 24 : &{trap {throw "$($_)"};[void]$Root.get_Name()}


    This line does test the ActiveDirectory Connection by getting the name Property and use a Trap block to catch it and throwing the Error again so the script will stop if this fails. 


    Line 49,64 :$btnCancel.add_Click({$script:Return = $false ; $form.close()})


    The add_Click methods handle the event when I button gets clicked you can give this funtion a Delegate ScriptBlock that gets executed every time the button get clicked.


    Line 75-95 : $TV.add_AfterSelect({


    This whole Scriptblock is also an eventhandler delegate, this one from the Treeview object and it is called every time a TreeNode is selected,


    you can see there is a variable with the name $This, this will contain the TreeView object so we can get the treenode that is selected at that moment from that


    Line 76 : if ($this.SelectedNode.tag -eq "NotEnumerated")


    we check if we already did get the children of this node, otherwise we will collect them and add SubNodes to the TreeView for them.


    Line 109 : $form.AcceptButton =  $btnSelect


    Make The Select Button the Default so it will get a click event when [Enter] is pressed


    Line 111 : $Form.Add_Shown({$form.Activate()})


    Used to give the form focus


    Line 120 : The logic to make the script "Hybrid"


    For more info about the AD parts see the rest of the series,


    For more info about building GUI's and placing and using Form elements on them in PowerShell See my Other GUI examples in former posts.


    Using a DataGrid :


    PowerShell out-DataGrid update and more DataSet utilities


    Using a Property Grid (Object Viewer)


    PowerShell-out-propertygrid-msh-view.html


    about Focus the Form problem (updated version this script)


    Simple Show-Image function for Monad


    Adding menus etc ,


    MSH Concentration (scripting games part 4)


    MSH Minesweeper GUI game


    Hosting PowerShell in it.


    Hosting an MSH runspace from Monad


    Use For EventWatcher workaround (STA Thread ), and how to use Popup balloons.


    MSH directory watcher with popup-balloon


    There are a bit more posts to find, if you search on GUI on my blog.


    *Edit* as the lineNumbers do stay if you copy the Code Above and pasting it, So I'm posting the code another time without LineNumbers


    Enjoy,


    greetings /\/\o\/\/
    Tags : Monad msh PowerShell


     



    Repost code from Notepad,without LineNumbers hope this works as well LiveWrite as Blogger hangs, on toughing this post ;-(


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

    Monday, September 04, 2006

     


    PowerShell



    "$([char[]]( (2    *  40  )  ,
    (100   +   11                 ) ,
    (99   +   8   +   12       )   ,
    (10   *   10 +   1  )     ,
    (  114                   ),
    83         )   ,
        (   100 +  4           )   ,
    (50 +    50   +    1      )   ,
    (30   +   70  + 8        )   ,
    (9    + 99       )  
    )
    )
    "



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

    Sunday, September 03, 2006

     


    PowerShell : How Do I randomize a list, and remove some elements ?



    Going on from last 2 posts,

    PowerShell : How can I tell whitch numbers are missing from a sequence of numbers found in a text file ?

    PowerShell : Can you do that less cryptic ?

    about finding missing elements in a sequence, inspired by a Hey Scripting guy, article : PowerShell : How can I tell witch numbers are missing from a sequence of numbers found in a text file ? , and the Sort problem mentioned.

    I came to another nice challenge, creating a test file for it, that is random and with some missing numbers,

     I made a remark about speed, (edit 3) in the second post, as on IRC we where comparing other methods and speed differences between the Methods used, you can find the examples at the end of the second post.

    But with so little numbers (10) in the original file, it is hard to test,

    So I made up some PowerShell commands to make a bigger testfile for this, for example to test the speed of the filereading and the sort, so if you past this code into the PowerShell console It will create a testfile of 1900 numbers from 1 to 2000 in Random order and with 100 missing numbers :

    Below the Code you will find the results when I did paste this code into my Console with some remarks to explain what is going on here :

     

    # Write the test Numbers to the file 

    1..2000 | sc c:\powershell\test.txt

    # Read them back in an ArrayList

    [collections.arraylist]$a=[io.file]::ReadAllLines('c:\powershell\test.txt')

    # put them in random order and remove 100 to create the gaps

    $r = ($a.count - 100)..1 |% {$R = new-object random}{$R.next(0,$a.count) |%{$a[$_];$a.removeat($_)}} 

    # Test the Times for sorting 

    (measure-command {$r | sort {[int]$_}}).TotalMilliseconds
    (measure-command {[array]::sort($r)}).TotalMilliseconds

    # Write the Randomized numbers back to the file

    $r | sc c:\powershell\test.txt

    # Test the complete Command

    (Measure-Command {gc test.txt | sort {[int]$_} |% {$i = 1}{while ($i -lt $_){$i;$i++};$i++}}).TotalMilliseconds

    # Test the Alternate Version

    (Measure-Command {
      [int[]]$a=[io.file]::ReadAllLines('c:\powershell\test.txt')
      [array]::sort($a)
      $a |% {$i = 1}{while ($i -lt $_){$i;$i++};$i++}
    }).TotalMilliseconds

     

    And here the results of this :

     

    PoSH># Write the test Numbers to the file
    PoSH>
    PoSH>1..2000 | sc c:\powershell\test.txt
    PoSH>
    PoSH># Read them back in an Array
    PoSH>
    PoSH>[collections.arraylist]$a=[io.file]::ReadAllLines('c:\powershell\test.txt')
    PoSH>
    PoSH># put them in random order and remove 100 to create the gaps
    PoSH>
    PoSH>$r = ($a.count - 100)..1 |% {$R = new-object random}{$R.next(0,$a.count) |%{$a[$_];$a.removeat($_)}}
    PoSH>

    This last line is the most interesting line where the magic happens, but the start of this "magic" is in the line before already, not the method of reading the file but the : [collections.arraylist]$a that will cast the result into an arraylist, In an arraylist you can add and remove Items, we make use of that in the next line.

    $r will take the results, as the $a array will be empty at the end of the command, next part is : 

    ($a.count - 100)..1 this will make a range from 1900 to 1, as the first line created a file with 2000 lines, but we want 100 less, if you just want to randomize the list just remove the -100 and all the numbers will stay and the list will only be randomized.

    Next |% The Foreach, then the first scriptblock,  {$R = new-object random} , this will generate a new random generator for more info see, Thow Dices in MSH , and 2 GUI games I made before that use it :  MSH Minesweeper GUI game ,MSH Concentration (scripting games part 4) ,

    As this scriptblock is followed by another one the Foreach will treat this as a Begin Block and only execute this once, then will execute the next scriptblock as a process block, $R.next(0,$a.count) |%

    This will create a random number from 0 to 1999 , and that is pipelined to the next scriptblock, note that the value on the pipeline is not used here, it just is used to determine the times to loop.

    The random number is now passed on to the next scriptblock, $a[$_];$a.removeat($_) it takes the random number from the pipeline ($_), and outputs the item that is at that place in the Arraylist $a{$_}, next it will remove the Item that it did output from the Arraylist $a.removeat($_) that is where the base of the magic is hidden,

    what, that's all remove an Item ?, Yep ;-),

    As next, the loop will go on to the second pass, and will come here again $R.next(0,$a.count) but as we did remove the item that we did output, this will be a number from 0 to 1998,

    So we will never output a double item, as we use the random number just as an Index, the trick with the 100 numbers to leave out is also based on that we just miss the last 100 numbers that remain AFTER we picked the numbers at random and that we did put in the $R array already:

    Lets list the first 10 to show that this did work :

    PoSH>$r[1..10]
    61
    1343
    1108
    1527
    762
    1039
    277
    295
    475
    1155

    Now we can do out first test with the randomized list,


    PoSH># Test the Times for sorting
    PoSH>
    PoSH>(measure-command {$r | sort {[int]$_}}).TotalMilliseconds
    1553.9698
    PoSH>(measure-command {[array]::sort($r)}).TotalMilliseconds
    5.7518

    Hmm, we already see some difference, but for testing our solutions for the question, we also want to test the reading of the file so we write the new list back to the file :

    PoSH># Write the Randomized numbers back to the file
    PoSH>
    PoSH>$r | sc c:\powershell\test.txt
    PoSH>

    Now that we are here, we have created our testfile, and  we can go on test the complete solution against a 1900 records random file with 100 numbers missing (I removed some of the output, but you can see the numbers are random missing :

     

    PoSH>[int[]]$a=[io.file]::ReadAllLines('c:\powershell\test.txt')
    PoSH>[array]::sort($a)
    PoSH>$a |% {$i = 1}{while ($i -lt $_){$i;$i++};$i++}
    6
    23
    29
    61
    73
    129
    207
    234
    241

    So Now we can go on and compare the speed of some different solutions for the question against a bigger file

    PoSH># Test the complete Command
    PoSH>
    PoSH>(Measure-Command {gc test.txt | sort {[int]$_} |% {$i = 1}{while ($i -lt $_){$i;$i++};$i++}}).TotalMilliseconds
    1814.0741
    PoSH>
    PoSH>(Measure-Command {
    >> [int[]]$a=[io.file]::ReadAllLines('c:\powershell\test.txt')
    >> [array]::sort($a)
    >> $a |% {$i = 1}{while ($i -lt $_){$i;$i++};$i++}
    >> }).TotalMilliseconds
    >>
    307.5865

     

    As you can see there can be some differences here ;-)

    If you like to do some more testing, also take a look in the PowerShell : Can you do that less cryptic ?  post for some more different ways to solve the question

    At the end of the post the 2 examples using Diff (compare-Object), and 1 using for to solve it, you can also compare them for speed

     

    Enjoy your testing and timing ,

    If you have other any interesting results (in speed or other ways) or other methods to handle the missing numbers problem, or randomize a list solution,  please leave them in the comments,

     

    Greetings, /\/\o\/\/
    Tags : Monad msh PowerShell


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

    Saturday, September 02, 2006

     


    PowerShell : Can you do that less cryptic ?



    Ok,Oh, all right

    the onliner from last post (" PowerShell : How can I tell witch numbers are missing from a sequence of numbers found in a text file ?  ,

    gc test.txt | sort {[int]$_} |% {$i = 1}{while ($i -lt $_){$i;$i++};$i++}

    was maybe a bit to tiny to post without any explanation.

    you can do very powerfull things on the commandline like this, but for in a script or example this might not very handy.

     I still not going to explain it,

    but I will make it a lot more Clear what Happens, by showing that you do not have too be so tiny in PowerShell , you can write this in a more verbose and readable way , as the former one-liner Can also be written as Follows :

     

    # Read numbers from file 

    $numbers = get-content test.txt

    # Sort the Numbers

    $Sortednumbers = $Numbers | Sort {[int]$_}

    # start comparing numbers in file to counter

    $counter = 1

    foreach ($number in $Sortednumbers ) {

      # as long as Number in file is higher than counter, output as missing and raise counter  

      while ($counter -lt $Number){
        "$Counter is missing"
         $Counter++
      }

      # counter is the same as Number, hence is in file output and raise counter

      "$Counter is In file"
      $Counter++

    }

     This code does exactly the same as the on-liner, is a bit more work, but much more clear for code you or somebody else might have to read or change.

    *Edit* some other suggestions given on IRC for handling this question are :

     

    # Other suggestions on IRC
     
    # <dreeschkind> 

    $n = gc test.txt
    $n|%{[int]$max = 1}{if ($max -lt $_){$max=$_}}
    diff -r $(1..$max) $n

    # <mow001> slower

    $n = gc test.txt
    $max = ($n | Measure-Object -max).maximum
    diff -r $(1..$max) $n

    # <d2d> faster ?
     
    $result = @(); $arr = Get-Content test.txt; for ($i = 1; $i -lt $arr[-1]; $i++) { if ($arr -notcontains $i) { $result += $i } }; $result

    *Edit 2*  Another tip : Need for speed, use another cool feature from Powershell go .NET directly : 

    [int[]]$a=[io.file]::ReadAllLines('c:\powershell\test.txt')
    [array]::sort($a)

    Enjoy,

    Greetings, /\/\o\/\/
    Tags : Monad msh PowerShell




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


    PowerShell : How can I tell whitch numbers are missing from a sequence of numbers found in a text file ?



     Another Hey Scripting Guy ! Question I could not refuse ;-)

    How Can I Tell Which Numbers Are Missing From a Sequence of Numbers Found in a Text File? In Powershell ?

    let’s make a text file containing the following sequence of numbers:

     

    # Make a TextFile with the Numbers

    @'
    2
    4
    8
    9
    10
    '@ | sc test.txt

     

    How are we going to determine which numbers (1, 3, 5, 6, and 7) are missing from the sequence? Like this:

    gc test.txt |% {$i = 1}{while ($i -lt $_){$i;$i++};$i++}

     

    PoSH>gc test.txt |% {$i = 1}{while ($i -lt $_){$i;$i++};$i++}
    1
    3
    5
    6
    7

    What’s that? Explain how this script works? Come on, SG; didn’t we mention that it was Saturday?

    *Edit* did I hear someone say Sort ? (thx Karl)

    *Edit2* Added from file with cast to INTEGER

    gc test.txt | sort {[int]$_} |% {$i = 1}{while ($i -lt $_){$i;$i++};$i++}

    PoSH>2,9,4,8,10 | sort |% {$i = 1}{while ($i -lt $_){$i;$i++};$i++}
    1
    3
    5
    6
    7

     

    *Edit3*, Ok, still no explanation but this might help understanding how this script works :  PowerShell : Can you do that less cryptic ?

    Enjoy,

    Greetings, /\/\o\/\/
    Tags : Monad msh PowerShell




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


    PowerShell Active Directory Browser teaser



    PowerShell Active Directory Browser teaser To test the upload of pictures in Live Writer Beta, a teaser for my next post in the AD series,

    Enjoy,

    Greetings, /\/\o\/\/
    Tags : Monad msh PowerShell




    posted by /\/\o\/\/
     0 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?