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 )
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
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.
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
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')
TruePS 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> $userdistinguishedName
-----------------
{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
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
From Loren Bandiera’s weblog I found the Lang.NET Symposium page
with on that :.
I'm watching en enjoying it at the moment,
Recomended !!
Enjoy,
Greetings, /\/\o\/\/
Tags : Monad msh PowerShell
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>$MowMoveddistinguishedName
-----------------
{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>$mowdistinguishedName
-----------------
{DC=mow,DC=local}PoSH>$mow.set_path('LDAP://CN=mow,OU=MowOu,DC=mow,DC=local')
PoSH>$mowdistinguishedName
-----------------
{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
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 : Stoppedname : 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>$htName 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')
FalsePoSH>$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 | gmTypeName: System.Collections.Hashtable
PoSH>[System.Collections.ArrayList](1,2)
1
2PoSH>,[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 | gmTypeName: System.Collections.Stack
PoSH>$sl = new System.Collections.SortedList
PoSH>Get-Member -InputObject $slTypeName: System.Collections.SortedList
PoSH>$q = [System.Collections.Queue]('a','b')
PoSH>$q.Dequeue()
a
PoSH>,$q | gmTypeName: 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
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:
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
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.
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 :
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)
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
Going on from last 2 posts,
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 :
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
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 :
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 :
*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
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
Enjoy,
Greetings, /\/\o\/\/
Tags : Monad msh PowerShell
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