Microsoft Operations Manager 2007(MOM2007), will be build on powershell, so there will be Cmdlets to manage MOM2007 and everything you can do in the GUI you can do in PowerShell.As I'm Implementing a MOM2005 environment as MOM2007 is still in Beta. So we have to miss the MOM Management Shell (Snap-In) and all those nice Cmdlets as shown at TechEd .
But then again........ Maybe not .
As I had a very good experience with using a .NET DLL from the SMS 2003 SDK (Microsoft.SystemsManagementServer.Automation.dll) See : PowerShell and SMS 2003
I Downloaded the MOM SDK, but no DLL so did look at the .NET examples in the SDK , and what seems to be the Case the are allready there, under the MOM programs directory is allready a SDK bin directory, from the examples I did learn that you needed 2 DLL's : Microsoft.Mom.Sdk.dll and mom.context.dll , on My Workstation I could only find Microsoft.Mom.Sdk.dll , but on the MOM ManagementServer the latter was also there, I tried copying it to my client but that did not work, So I installed PowerShell on the Server (As I was lucky that it is our server not the customers I was able to do that) .
And as the DLL's are allready there I needed only this 3 "Magic Lines" and my MOM2005 Management Server was "PowerShell Enabled".
# PowerShell Enable MOM2005 # /\/\o\/\/ 2006 # (works only on MOM managentserver)
$mom.GetComputerGroups() | ft name,ComputerIncludeList
#get agents and states :
$mom.GetAgentManagedComputers() | FT Name,State
# get rulegroups
$mom.GetRuleGroups()
From here on as you also can see in the Acive Directory series I currently running, its easy to learn from the Object itself using Get-Member (see example above when you run it) and to construct easy Functions to mimic the MOM2007 CDMlets. e.g. :
PoSH>$mom.GetAgentManagedComputers() | FT NAME,STATE
Name State ---- ----- MS001 Error MS002 Error MS012 Warning MS046 Success MS047 Success MS048 Success
# Make it a Function :
Function get-MomAgentManagedComputers { $mom.GetAgentManagedComputers() | FT NAME,STATE }
Or as is almost just as easy for most task just just the variable and create (Sub) variables ;-)
# Get RuleGroups
PoSH> $mom.GetRuleGroups()
ID Name Description Enabled -- ---- ----------- ------- 8fff-00... Dell OpenManage Processing rule group for ... True b050-31... Microsoft Baseline Securit... Microsoft Baseline Securit... True 976a-ca... Microsoft Operations Manager True afa4-50... Microsoft Operations Manag... Checks that installed MP v... True a7af-00... Microsoft SQL Server Container for rules to mon... True 87ec-00... Microsoft Windows Internet... Container for rules to mon... True be95-91... Microsoft Windows Print Se... Microsoft Windows Print Se... True bb02-42... Microsoft Windows Server 2... Container for rules to mon... True 8b4c-ca... Microsoft Windows Server C... Microsoft Windows Server C... True 8803-00... Microsoft Windows Servers ... Microsoft Windows Servers ... True
Id Name Description Enabled -- ---- ----------- ------- 8fff-00... Dell OpenManage Processing rule group for ... True
# and a "$dell | get-member" did learn us that we could do this :
PoSH> $dell.GetSubRuleGroups()
Id Name Description Enabled -- ---- ----------- ------- 9b9d-32... State Monitoring and Servi... Rules for Dell state monit... True 98e4-4a... Array Manager Processing rules for Dell ... True af8e-57... Discovery Discovery of Dell Computers True b914-68... Management Servers Dell Management Pack Rules... True 9613-87... Server Administrator Processing rules for Serve... True 8573-af... Storage Management Processing rules for Dell ... True
# and so on :
PoSH> $DellStor.GetRules() | ft name,Enabled
Name Enabled ---- ------- Dell_OM_SM Device is missing True Dell_OM_SM Virtual disk initialization failed True Dell_OM_SM Predictive Failure reported True Dell_OM_SM Enclosure power supply has an DC failure True Dell_OM_SM Enclosure firmware mismatch
PoSH> $DellStor.GetRules()[0]
Id : 05073db6ddca Name : Dell_OM_SM Device is missing Enabled : True EnabledOverride : AppliedEnabledOverride : Scripts : {DellOMSALaunch, Dell RAC Console Launch} RuleThreshold :
# And use the PowerShell Formatting tricks :
# a quick and dirty list of all the computers in the ComputerGroups
This one of the think I love most in MSH and why it is so great, - find a SDK, - look for the .NET DLL's - load them in the Shell, - get an .NET Object - ask what it can do .. - and of you go .... You can start exploring and learning on the Job.
And again... we don't have to wait for the next version (MOM or PoSH), we can make a headstart.
If there is someone that knows a way to do this on the client (getting a mom.context.dll that works on the client I think is needed) that would be realy great, so if any MOM guru is reading this, and knows how to do this, please leave a comment.
In this second part of the PowerShell and Active Directory series, we go on from PowerShel and Active Directory Part 1 (Sorry for the Typo) A quick refresh and commands needed to get back in that state :
Also we did see that we can use format-list * / format-Table * to list all the properties, and that we can get the members and Properties by using get-member. also you could see that the DirectoryEntry Object is a Wrapper that can contain different kinds of AD Objects, e.g. : Domain,OU,User (and if you did follow my advice and did some "browsing" on your own you could see that that goes also for Groups and other objects). We learned that its always good to check the type of the object that we get back as sometimes it's a bit different that that we expect, also we did see how to use get-member to get the methods of an object that is enumerable.
In this second part we are going to create a user. and then create a 100 of them and set some more properties.
as in this part of the series we going to write to the ActiveDirectory it might not be a good Idea to do it in a Production environment, or you might not have an AD present and still want to follow the series, for the Demo I did use a VM with a domain controller but you can also use ADAM (AD application Mode) that you can install on your own workstation to test.
(PS nope I did not work on the AD provider anymore and it might take a while before I do, Sorry not enough insomnia time)
also you can find an example to create the MowOU in that post, from there on you can follow the series, only the "automatic" connection to the Domain will not work, you need to give the LDAP path in the DirectoryEntry Constructor, as explained that post.
So after you connected to the Test OU of your choice, let's go on Creating a User
As we have see in former post, the Get_Children() Method of Returns a DirectoryEntries Object, and as I hinted or you might have see in the get-member output this Object also has a Add Method, let's find out how that does work :
You call a method in PowerShell with () behind it, if you leave them away as I did above you get some info about the Method, especially the OverloadDefinitions is very valuable, in this case it shows us that the Add method has one overload and it takes a string name and a string SchemaClassName.
Exception calling "Find" with "1" argument(s): "There is no such object on the server. (Exception from HRESULT: 0x80072030)" At line:1char:27 + $mowou.get_Children().find( <<<< "CN=Mow2")
Note that it absolutely needed that you use a variable here as the User Will not be created until you call the CommitChanges Method, you can see that from the first output that the DN name is not yet filled, and if you throw it to the pipeline you can not call the commintChanges() Method, that why you need the variable for this. OK, OK not completely you can do it also like this ;-) :
# Make an OU PoSH>($mowou.get_Children().add("OU=MowSubOu",'organizationalUnit')).CommitChanges() PoSH>$mowou.get_Children().find("OU=MowSubOu")
For the example above you can let PowerShell first evaluate what is in the parents and then call a method on it, also you can see how to do the same for an OU.
OK, Let's do not one user (as they still can say they do it quicker in the MMC GUI, and to have some users to test on in later parts of this series), let's do a 100 (for readability I did 5 here on the blog)and name them MowTest001 to MowTest100 and do not use a script but just go on from the commandline.
first lets count to 100, in PowerShell we have a nice range-operator ".." for this :
PoSH>1..5 1 2 3 4 5
Then we can use a pipeline and Foreach (by alias %) :
PoSH>1..5 |% {$_} 1 2 3 4 5
and then use a string and and the -F (format) operator in PowerShell, to format the numbers with trailing zeros and add them to a string, first the {0} inserts the first parameter, and then you can also use the .NET formatstrings to format them.
And here (as mentioned in that post also) you can find a good reference for formattingStrings in .NET : (This is a different one from the one in Jeffrey Snovers's post with some more info !) Standard Numeric Format Strings
I had some problems with this in the Demo (I turned string and parameter arround) so it might have not been that clear in the Demo, on the other hand it shows how you can play with a line till you have it right by using the up arrow.( and it was cool for a time to call out : Jeffrey Help ! and he DOES show up to help me out LOL ;-))
then if you get it right you can make a loop and use the History of your commandsettings to add former commands to the loop, it might be a bit hard to show on paper but the trick was to open the loop, and walk back with the up arrow in you history, edit add former commands you did to the loop, then close it with }[enter][enter] (you need a blank line after it).
# if you add another foreach and curly braces open and press enter you get a >> Prompt
working correct at the time, but not when I did change it to $mowou.get_Children().add('CN=$_','User') in the loop.
What went wrong ?
As we did create 100 Users, but there is a bit more work to be done (filling properties and Enable them for example), I will get on to that in the next post, and to format and list the created objects, also You might have noticed the examples in the Adam post where a bit different, I will explain why also in the next post, after that we will look at taking import for SQL or CSV for example and searching AD.
In my 200th post already (as I did just see) as promised here the start of the Active Directory Management series.
In this first Part I will show how to make a Active Directory Object in Powershell, connect to a domain, list Properties and Methods of the Object, and how to get the child Objects and store them in a Variable again.We will do all of this interactive from the commandline,
there are no CMDlets yet for Active directory management in PowerShell for version 1, but as we can use .NET objects from powershell we are still able to manage Activedirectory from Powershell.
the .NET Classes we need are in the namespace system.directoryservices.. (This naming is because as you can connect not only to AD but to an other directoryservices using LDAP as well. ) in .net 2.0 we also have a activedirectory namespace for infrastructure management but more about that later in the Series.
The object we are going to use for this is called a Directoryentry.
So let's start by making a connection to Active Directory. by creating an DirectoryEntry object, as you might have seen before, to get a .NET object we need the command new-object :
*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.
and as you can see as a result we get back the distinguishedName of the domain,
there are 2 things to note here,
you can see that the directoryentry constructed without parameters defaults to the default naming context, that is the current domain, in this case mow.local .
second thing to note is that as we just throw the object to the pipeline, so it gets the default formatting and after that its gone.
as I want to use it a bit more, I will put it into a variable so we can keep using it. I just use the arrow-up to get the previous line again, and Home to get to the beginning of the line and type '[variablename] = '. in front of it. I like to work this way to first check if I get back the object, and then if it is OK I put it into a variable, otherwise I need to check the variable everytime to see if the command succeeded.
as this is connecting us to the root namespace of the domain, I will call the variable $root.
Nice just what I needed as there is not much to do in the root of the ActiveDirectory, so lets look if we can connect to one of the SubOU's You would expext that you can just use the indexer to get to the wanted OU from the Array returned like this :
PoSH> $root.get_Children()[6] Unable to index into an object of type System.DirectoryServices.DirectoryEntries. At line:1char:22
This does not work, you can see the reason for this in the Errormessage, we did not get back a collection of DirectoryEntry Objects, but one instance of another .NET class : System.DirectoryServices.DirectoryEntries You can also check on this by asking it for it's type :
# Check the type
$root.get_Children().GetType()
Note that normaly GM (Get_member) will not show this as it does enumerate the Object ( ?? and you just said that it was not a collection.. nope it is not and it has no indexer but it has a GetEnumerator() Method, so the pipeline of PowerShell does Enumerate on it, and get-member will show the members of the Items that got enumerated, but will show them only one for every type thrown to the pipeline)
PoSH> $root.get_Children() | gm
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()
you can also give the object as a parameter to get-member to avoid this Get-Member -inputObject $root
or a workaround I like is put a comma before the object (again as I can use "Arrow Up" to get the last line this change is much easier in interactive use when you need members of the collection not the instances):
but as you also might have seen in the get-member output, the directoryentries class also has a find method, that has a name as a parameter and. that will find and return a specific child
note that this is also a DirectoryEntry Object but it will have other properties as it as a OU Object not the domain.
and from here we can use the some method to list the objects (Users / Computers / Sub-OU's)
$mowou.get_children()
# and for example get a user into a variable to edit it etc :
$mow = $mowou.get_children().find('cn=mow')
note that this is not the only way to get to the sub-OU, If you know the LDAP Path you can pass it in the constructor and connect to the OU directly : (also note that you can leave away the system namespace as PowerShell will append it)
In the next part of this series we will create a User, and see how to create a loop to make more as 1 user at a time, and fill some more properties.
later in this series we will use the DirectorySearcher to do searches in AD
But for now by creating one .NET Object and only the 3 most basic PowerShell Cmdlets (new-object / format-(List/Table) / get-member ) we already can :
Connect to AD List properties of AD Objects List methods of AD Objects Walk to the Domain structure to wanted OU Connect directly to SubOU's List members of OU's
and the only thing we have to remember is that we need a directoryServices.DirectoryEntry Object. It will find out the domain / LDAP path for us if we do not know it, and we can use get-member to remember / learn us what the object can do.and to explore the objects we get back.
So as you see it is not as hard as i might seem being without Cmdlets.
More in next post, till then try walking to different parts of AD this way and look at Computer / Users Objects,and do Format-List * and get-Member on the returned objects, to get used to the DirectoryObject and learn for the output you get back, (for a preview of the next part Creating a user as in the Demo, note the Add() method on the directoryEntries class) Feel free to leave remarks or questions in the remarks.
First of course having the chance to meet Jeffrey Snover, the Windows PowerShell Architect was realy great and when we did also meet and spend some quality time (a couple of hours on a table with 3 open laptops exchanging a lot of info ;-) ) with Scott Hanselman on Sunday, after that in the evening the tech-check for the , and then dinner with Jeffrey in Boston.
my TechEd was allready made !
Then on monday, before the Windows PowerShell: Solving Management Problems session I did meet Don Jones who anounced PowerShell support in PrimalScript 4.1 in this session . and that is writing the book Windows PowerShell: TFM, you also you can find 2 interviews he did with Jeffrey Snover Here . And I also did a Small demo about ActiveDirectory management on stage. Tomorrow I will post the contents a bit more information about that in the first entry in a series about this as I decided to turn it into a series on the blog to cover a lot more AD stuff.
Also Jeffrey Snover's Tuesday morning session Windows PowerShell: Next Generation Command Line Scripting was great. and I did hear find a lot of good credits about it at TechEd, and in my PowerShell news collector after I got home ( there where a lot of powershell posts last weeks check also DontBotherMeWithSpam 's excellent powershell Links collection he keeps here : http://del.icio.us/powershell )
Scott Hanselmann also did 2 Lighting sessions about powerShell, I did see one of them it was realy great.
Vivek Sharma's Microsoft Exchange Server 2007: Management Shell and Scripting session was also very good (made seriously considering getting into Exchange again I didn't used since 5.5 and (never did regret) and what would be homework as I have no exchange at work ). the Mark Russinovich sessions where also great, the MOM 2007 PowerShell support. I did see some virtual machine management CMDlets for PowerShell (a hot topic at the moment). Some IronPhyton and RUBY (maybe some more about that in a later post) and much, much more interesting info.
Also I realy enjoyed the talks and powershell demoing between my sessions at the PowerShell Booth, snd all the People I had the chance to meet .
and ofcourse The Train Concert at Fenway park, and The Influencers party where amazing (I had to miss a cruise with Sapien that they where so kind to invite me for and I hid hear was also great ) ,
Tomorrow I will Start a series about Active directory management from PowerShell that will cover the demo material :
- How to use the .NET classes - Connect to AD - List SubOU's - Create a User - make a loop Create 100 Users (do some formatting and what went wrong ;-))
but with more background info.
and then going on from that in the followup parts (amongs others).
- filling more properties, - enabling the accounts. - connect to the schema to lost possible properties - using a directorySearcher to search AD - Large queries / group listings - Working with logondates - creating users from CSV - using activedirectory .NET classes to manage infrastructure. - making some small utility scripts
I will try to work from the very beginning and from there on to the more advanced sample scripts on my blog and how they work in a 5 - 10 parts series.
also I might change my blog hosting and the layout (after a lot of elbows from Scott Hanselmann on TechEd) so I can also make my blog more accessible, but this can take some time, more about this later.
All for us ungrateful scoundrels, making fun about him, and posting nasy comments about the Windows PowerShell Script Repository and the scripts in there.
for the ones that did see the Powershell session on Monday. thanks for the positive reactions and I will post a transcript of the AD demo in the beginning of next week. (as I do not have *doink* an electronic version handy.) and blogger did "eat"my first try of posting it (together with the bad wireless connections, so I use a public PC for this post).
till then you can find the tabcompletion Jeffrey and I did use in my last post here :
Also you can find me around the Powershell stand in the technical education section, between the sessions I go to, to answer questions or demo some PowerShell stuff.
*** I made this addition as the standard tabcompletion, does only expand methods and properties on the first level, and on hitting [tab] the what I did find very annoying.
this one I did add for new-object use, as a shortcut so that I can use tabcompletion on the -TypeName parameter, I type a '[' complete the typename, type '=' and [tab] and the braces are removed.
and here is the new function TabExpansion function :.
# TabExpansion.ps1 # Version 0.4 # Replacement of default TabExpansion function # /\/\o\/\/ 2006
function TabExpansion {
# This is the default function that gets called for tab expansion. # Edited by /\/\o\/\/ from the original to handle : # - Cached tab completion on types (janel / mow). # - Methods and properties of types # - shows get_ methods # - MultiLevel variable Tab Completion # - Bracet Removal # Edited by DBMwS: Added Progressbar and Scoped variable name expansion
# Handle expansions for both "Scope Variable Name" and "Type Variable Names" (DbmwS) '(.*^\$)(\w+):(\w*)$' { $type = $matches[2]; # function, variable, etc.. that are not scopes $prefix = $matches[1] + $type; # $ + function $typeName = $matches[3]; # e.g. in '$function:C', value will be 'C'
if ($_ScopeNames -contains $type) { # Scope Variable Name Expansion foreach ($scopeVariable in (Get-Variable "$($typeName)*" -Scope $type Sort-Object name)) { $prefix + ":" + $scopeVariable.Name } } else { # Type name expansion($function:, $variable, $env: ,etc) foreach ($t in (Get-ChildItem ($type + ":" + $typeName + '*') Sort-Object name)) { $prefix + ":" + $t.Name } } break; }
# Do completion on parameters (original) ... '^-([\w0-9]*)' { $pat = $matches[1] + '*'
# extract the command name from the string # first split the string into statements and pipeline elements # This doesnt handle strings however. $cmdlet = [regex]::Split($line, '[;]')[-1]
# Extract the trailing unclosed block if ($cmdlet -match '\{([^\{\}]*)$') { $cmdlet = $matches[1] }
# Extract the longest unclosed parenthetical expression... if ($cmdlet -match '\(([^()]*)$') { $cmdlet = $matches[1] }
# take the first space separated token of the remaining string # as the command to look up. Trim any leading or trailing spaces # so you dont get leading empty elements. $cmdlet = $cmdlet.Trim().Split()[0]
# now get the info object for it... $cmdlet = @(Get-Command -type 'cmdlet,alias' $cmdlet)[0]
# expand the parameter sets and emit the matching elements foreach ($n in $cmdlet.ParameterSets Select-Object -expand parameters) { $n = $n.name if ($n -like $pat) { '-' + $n } } break; } } # EO switch } # EO Process }
you can past al code to a PowerShell console, or save it to a file and start it dotsourced (from your profile):