Using PowerGUI® to manage security

One part of my job that I find particularly enjoyable is working closely with other members of the PowerShell Community.  It doesn’t take any time at all when working with these people to feel the passion and excitement that they have for Windows PowerShell and PowerGUI.  One such person I have been working with a fair amount recently is Vadims Podans.  Vadims is a PowerShell MVP from Latvia and you may have seen some of his work in the past on his blog or in the Enterprise PKI Management PowerPack that he entered in our PowerPack Challenge contest last year.  From my experience working with him I’ve come to learn that he knows a heck of a lot about PKI and security in general, not to mention PowerShell.  Vadims’ expertise in these areas has resulted in quite a few new security-related releases in the past several weeks, as follows:

AD-PKI Cmdlets Tech Brief

Quest Software recently published an AD-PKI Cmdlets tech brief that was written by Vadims.  This tech brief reviews the security concepts surrounding digital certificate management and provides details and many examples showing how the AD-PKI cmdlets can be used with Active Directory to simplify PKI management.

Download the AD-PKI Cmdlet Tech Brief here.

Enterprise PKI Management PowerPack

Vadims recently released version 1.5 of his Enterprise PKI Management PowerPack.  This update includes support for the AD-PKI cmdlets that were introduced as part of the 1.4 release of the Quest AD cmdlets.  Notable features listed on the PowerPack page include:

  • A lot of code now uses native Quest AD Cmdlets (version 1.4.2) so the PowerPack demonstrates new PKI cmdlets in action!
  • Added additional error handling.
  • In Certification Authorities node added properties that contains helpful information about CA CRL status. In addition there was revisited View CRL action and renamed to View CRL Info
  • Added Active Directory PKI node that contains the most common AD PKI-related containers. You will be able to review container contents and publish/unpublish certificates/CRLs by using new actions.
  • Changed Enterprise OCSP location behavior. Now the PowerPack realizes the same behavior as it is implemented in pkiview.msc MMC snap-in. Now the PowerPack correctly retrieves all available Enterprise OCSP Responders even if they are not running CA service
  • For Certificates node added two subcontainers (subnodes, as shown in the last screenshot) — Certificates and CRLs. This allows you to browse both — certificates and CRLs in the local certificate store. For CRLs added new basic actions.
  • Revisited certificate export and import actions. In addition to Quest AD cmdlet usage, the interface is provided in GUI form. So now you will be able to use standard dialogs to select a file to save/open.

Learn more and download the Enterprise PKI Management PowerPack here.

Script Signing Add-on

Very shortly after I released the first version of the Script Signing Add-on for the PowerGUI Script Editor, Vadims provided me with some great feedback that I was finally able to incorporate into an update.  Yesterday I released version 1.1 of this Add-on, which includes the following changes:

  • Replaced “Test Certificate” functionality with View Signature, allowing users to view script signing certificates used to sign files in the native Windows Certificate properties dialog.
  • Added View Certificate support to the Script Signing Options dialog.
  • Changed the default signing method to include all certificates in the certificate chain.
  • Optimized the script signing certificate search algorithm so that it only searches for script signing certificates in the My containers.

Learn more and download the latest version of the Script Signing Add-on here.

And if that’s not enough for you, you can also keep your scripts secure by using the integrated source control functionality in the Script Editor in PowerGUI Pro so that you can track any and all changes that are made to your scripts whether they are signed or not!

Please let us know what you think of these and other releases, as well as what you would like to see us add in the future, either here or on the PowerGUI Forums.  The feedback system really works!

Kirk out.

Share this post:

Create your own org chart from AD with PowerGUI!

Another week has gone by and I have another brand new PowerPack ready for download.  This time around it’s the Org Chart PowerPack.  This is a PowerPack that I put together based on a Get-OrgChart function I wrote to analyze org chart data at work.  It lets you do some really cool things such as:

  1. Dynamically create an org chart from users in Active Directory using title, department, office, address, and other properties.
  2. Generate a Visio Org Chart from PowerGUI for the any branch of an organization.
  3. Create statistical reports for the employees in your organization to see breakdowns of employees by office, department, management, etc.
  4. Dynamically generate Office Directory reports in HTML when using it in conjunction with the Advanced Reporting PowerPack.

Note: The Org Chart PowerPack uses the Quest AD cmdlets to retrieve information from AD so you will need to install those first before you can use the PowerPack.

If you would like to see how this PowerPack can be of benefit to you, check out this screencast:

This screencast was recorded in HD format so you can click on the HD button once you start watching it to enable high definition video.  Alternatively, if you would prefer to watch a high resolution flash version with a table of contents you can watch the screencast here.  I decided to try widescreen format this time since that is my format preference…let me know if this is a problem for you.

This is the first release of this PowerPack and I’m anxious to hear what you think so please give it a look and share your feedback so that I can improve it with another update in the future.

Thanks for listening!

Kirk out.

Share this post:

PowerShell Quick Tip: Setting AD object attributes with ScriptBlock parameters

In PowerShell you can pass pipeline data to parameters that are not configured to accept pipeline input using ScriptBlock parameters.  This has been discussed before and it is well worth your time to make yourself familiar with that capability of PowerShell because it allows you to create true one-liners in places where you might think you cannot.  Basically it boils down to this: you can pass a script block into parameters in a cmdlet that is not of type script block and within the script block you provide the $_ variable will contain the object that was just passed down the pipeline.  The script block will be evaluated first, and then the result will be passed into the cmdlet parameter.

Still, even with that knowledge in hand people often trip over the ScriptBlock parameter syntax when using a parameter that takes a hash table (aka an associative array) as input.  The most common example I can think of where this is encountered is in the Quest AD cmdlets.

Many of the Quest AD cmdlets have a parameter called ObjectAttributes.  This parameter serves two purposes: in Get cmdlets it is used to define the values you want to filter on; in Set and New cmdlets it is used to define the values you want to assign to specific attributes.  Not consistent, I know, but that’s a whole other discussion.  In both cases the ObjectAttributes parameter is a hash table and to use it you simply need to define a hash table that matches attribute names with values.  Here’s an example showing how users trip over the syntax without realizing it:

Get-QADComputer Comp1 `
    | Set-QADObject -ObjectAttributes ` 
        @{userAccountControl=$_.userAccountControl -bxor 2}

This one liner was designed to enable or disable a computer object in AD.  It will run without raising an error, and it will even enable or disable the computer object, but it will not work like you might expect.  After running this command the userAccountControl attribute (which contains many flags, not just a flag for enabled/disabled state) will not be properly configured.  Why?  It looks like it is properly using a ScriptBlock parameter, but it is not so the $_.userAccountControl value will either evaluate to 0 if the $_ variable is null or if it does not have a userAccountControl property, or it will contain the userAccountControl value from whatever object the $_ variable contained before you called Get-QADComputer in the first stage of this pipeline.  Nothing in this command instructs PowerShell to treat the ObjectAttributes parameter as a ScriptBlock parameter.  So what’s missing?

The most important thing to remember about ScriptBlock parameters is that they always must be surrounded by script block enclosures (“{“ and “}”).  Otherwise they are not script blocks.  In our example above it looks like the parameter is surrounded by the proper enclosures, but that’s not true.  It’s surrounded by hash table enclosures (“@{“ and “}”), and this is what trips people up when working with this syntax.  To make this be properly treated as a ScriptBlock parameter, we need to surround the hash table with curly braces, like this:

Get-QADComputer Comp1 `
    | Set-QADObject -ObjectAttributes ` 
        {@{userAccountControl=$_.userAccountControl -bxor 2}}

That makes PowerShell recognize that we have a ScriptBlock parameter and the $_ variable within it properly evaluates to the object that just came down the pipeline.  No ForEach-Object or temporary variables required.  It seems simple enough when explaining it but you’d be surprised how many people get tripped up on this syntax.

If you want to see some forum discussions where this has been an issue for others, you can go here or here.

Kirk out.

Share this post:

The Active Directory PowerPack, the Quest AD cmdlets, and what can happen when you change public object interfaces or cmdlet parameter attributes in PowerShell

This is about what can happen when things go wrong and what not to do so that things don’t go wrong.

In case you didn’t know, I work at Quest Software on the PowerGUI Team.  My position is rather unique because I work exclusively with Windows PowerShell, and I don’t think there are too many jobs out there that offer that experience.  The main focus of my job is to create and extend PowerPacks, which are collections of PowerShell scripts that are packaged together to define an extension to the customizable PowerGUI Admin Console.  The scripts in the PowerPacks I create range anywhere from the extremely simple (one cmdlet or function call) to the very complicated (a script that calls into one or more functions that span many thousands of lines of PowerShell script).

Among others, one of the PowerPacks that I manage is the Active Directory PowerPack.  The Active Directory PowerPack provides a management interface to Active Directory, and it uses the Quest AD cmdlets in its PowerShell scripts to do the actual management of Active Directory.  For quite a few reasons1,  I need to explicitly indicate which connection should be used when you use that PowerPack to do something with Active Directory, regardless of what it is you are doing.  This means I am absolutely dependent on being able to determine what connection should be used in any script that is included in the PowerPack.  For scripts that are used at the beginning of a pipeline I look for the appropriate connection information that is stored globally.  For other scripts that are used later in a pipeline with Quest AD cmdlets I look at the Connection property that is attached to the objects coming down the pipeline.  This model has worked very well until recently when something unexpected happened.

Almost two weeks ago, just after version 1.2 of the Quest AD cmdlets was released, it came to my attention that the Connection property that I am so dependent on was not included on objects in that release.  For those of you who are not developers, this type of change (changing a public interface in an SDK) is very bad news.  It is called a breaking change, and the name is very fitting – the Active Directory PowerPack started breaking all over the place for users who upgraded their Quest AD cmdlets to version 1.2!

Amid a flurry of email discussions between myself and the Quest AD cmdlets team I spent the next week and a bit putting together an update to the Active Directory PowerPack so that it would work despite these changes, basically putting the Connection property there myself if it isn’t there.  At the same time, the Quest AD cmdlets team quickly started work on a 1.2.1 patch release to put the Connection property back in so that scripts outside of PowerGUI that use that property wouldn’t be affected either.  The patch for the Quest AD cmdlets is not available yet, but the updated Active Directory PowerPack, and the updated Network PowerPack which also used the Quest AD cmdlets a fair amount and was therefore susceptible to this change, are now posted in the PowerPack library and available for download.  If you use these PowerPacks, I strongly recommend you download and import the most recent releases of each of these PowerPacks.  Their document page in the PowerPack library contains all of the information you need to upgrade your PowerPacks and get started using the new versions.

Now that I have finished dealing with the impact of a breaking change like this one and the unpleasant work that ensues,  I thought it would be worthwhile to share with others what exactly consititutes a breaking change in a PowerShell cmdlet or advanced function.  The following is a list of 13 rules that you should adhere to when updating your cmdlets or advanced functions if you want to avoid introducing breaking changes:

  1. Do not remove any published parameters that are included in your published cmdlets or advanced functions.
  2. Do not rename any published parameters that are included in your published cmdlets or advanced functions unless you add an alias to the parameter that is the old parameter name.
  3. Do not reduce or remove pipeline support for any published parameters in your published cmdlets or advanced functions that support pipeline input.
  4. Do not remove support for $null input for any published parameters in your published cmdlets or advanced functions that support $null input.
  5. Do not modify the default value for any published parameters in your published cmdlets or advanced functions unless that modification will not change how the command functions in existing scripts.
  6. Do not add a required flag to any parameter in published parameter sets in your published cmdlets or advanced functions.
  7. Do not modify the position of any published parameters in published parameter sets in your published cmdlets or advanced functions.
  8. Do not replace the associated object type with an incompatible type for any published parameters in your published cmdlets or advanced functions.
  9. Do not remove wildcard support for any published parameters in your published cmdlets or advanced functions that have wildcard support.
  10. Do not remove support for building the value from the remaining arguments in any published parameters in your published cmdlets or advanced functions that support building the value in this manner.
  11. Do not remove any of your published parameters from published parameter sets in your published cmdlets or advanced functions.
  12. Do not increase validation restrictions for any of your published parameters in your published cmdlets or advanced functions that have validation restrictions.
  13. Do not modify or remove aliases for any published parameters in your published cmdlets or advanced functions.

Additionally you need to pay attention to the objects that are returned by your cmdlets or advanced functions so that you don’t introduce breaking changes on those either.  The following rules should be adhered to in order to avoid breaking changes on objects returned by your cmdlets or advanced functions:

  1. Do not remove a public property or method.
  2. Do not replace the types associated with a public property or method with incompatible types.
  3. Do not modify the order of the parameters in a public method.
  4. Do not add required parameters in a public method.

Not following these rules means risking breaking production scripts, risking making your customers unhappy, and many other potential undesirable consequences.  Please, if you are seriously trying to add value to the PowerShell ecosystem by extending it with additional commands, pay attention to these rules and don’t introduce breaking changes when you update them!

Thanks for listening!

Kirk out.

1 Reasons why the connection must be explicitly indicated in the Active Directory PowerPack:
1. The Quest AD cmdlets allow you to connect to many different directory services.
2. Opening a connection to a directory service with the Quest AD cmdlets changes a global variable that is used automatically by other cmdlets in the same snapin when you don’t explicitly indicate what connection to use.
3. In PowerGUI you can create or import other PowerPacks that may open their own connections to different directory services using the Quest AD cmdlets, Active Directory or otherwise.
4. In PowerShell, whether you are using the Quest AD cmdlets interactively or invoking a script that uses them, you are likely only working with one set of data from one directory service at a time in a logical manner.  Working in a user interface that is built on top of PowerShell is less restrictive, allowing you to move more freely between multiple data sets from multiple sources (directory services in this case) in what would be considered an illogical manner as far as script creation goes.

Share this post:

Provisioning users in Active Directory with PowerShell and the QAD cmdlets

As part of the EnergizeIT tour that I was on for the past three weeks, I did a quick introduction to PowerShell and then showed how the ability to automate tasks using PowerShell can make the job of an IT administrator much, much easier.  The scenario for the automation example I used was this: your HR department contacts you on Friday afternoon and tells you there are a bunch of new users coming in next week and you need to make the accounts right away.  The actual number is arbitrary because PowerShell scripts are the same for 1 user as they are for 1000000 users (exaggerated as that might be), but for my example I used a dozen users.

The point with this example was to show you how you can accomplish a task like this quickly regardless of the number of users being created and go home on time for date night, your son’s baseball game, etc.  This demonstration was very well received, and at the end of the demonstration I promised that I would post the script I wrote during the demo here in my blog.  The script that I post here may look slightly different from the script you saw me run at your tour event because I wanted to make sure shared the answer to a question someone asked me during the tour: How do I set the password for the new users when I create them?

For those of you who didn’t see the live demonstration, note that the csv file I used (C:\Users\Poshoholic\Documents\NewHires.csv) contained the following text:

FirstName,LastName,Title
Dmitry,Prosser,Software Developer 4
Oisin,Hill,Quality Analyst 1
Jeffrey,Shell,Senior Support Representative
Don,Munro,Software Developer 1
Charlie,Shaw,Project Manager
Marco,van Oursow,HR Assistant
Brandon,Russel,Product Manager
Keith,Hicks,Software Developer 3
Marc,Grehan,Product Marketing Manager
Karl,Jones,Quality Analyst 3
Kirk,Lee,Quality Analyst 1
Thomas,Sotnikov,IT Analyst 2

(FYI: if you think those names look familiar, I took the first names and last names of 12 PowerShell MVPs and mixed them up)

During the demonstration, the script below was built up iteratively within the PowerShell console so that you could see the thought process involved in creating a script that way.  In this blog post however, I’m simply going to post the finished script.  If you have questions about the demonstration or want to refresh your memory on how you could build a script like this iteratively, let me know.  The finished script to create the users from the csv file simply looks like this:

Import-Csv C:\Users\Poshoholic\Documents\NewHires.csv `
    |
Add-Member -Name Name -MemberType ScriptProperty -Value {$this.FirstName + + $this.LastName} -PassThru `
    |
Add-Member -Name SamAccountName -MemberType ScriptProperty -Value {($this.FirstName[0] + $this.LastName.Replace( ,)).SubString(0,20)} -PassThru `
    |
New-QADUser -City Ottawa -UserPassword P4$$w0rd -ParentContainer poshoholicstudios.com/users

Please note the following if you want to use this as a basis for your own script:

  1. You can copy this script from my blog and paste it directly into the PowerGUI Script Editor where you can customize it to meet your needs (be careful of the word wrap – there should be four lines of script once you paste it in PowerGUI).  Alternatively if you want the script already in a ps1 file, you can download it here.
  2. This example requires the Quest AD cmdlets to create the new users.  Once you have those installed, don’t forget to load them in PowerShell using Add-PSSnapin or in PowerGUI using Libraries in the File menu.
  3. This shows the finished script I built during the demonstration, with the addition of the assignment of the default user password value as P4$$w0rd.  Whatever you use for the default password value, it must meet your password requirements in your lab.
  4. If you want to run this without making changes, don’t forget to append -WhatIf at the end of the last line in the script.

Don’t be afraid to ask me questions about any of this, whether you need help customizing this script to make it work in your environment or just want an explanation of how the script works.  I’m always happy to help!

Kirk out.

Share this:

Essential PowerShell: Use non-portable console customizations sparingly

Isn’t it odd how issues with software are often raised in groups?  I’ve been helping people use software for a long time and I find it uncanny how when I come across an issue once, there are bound to be two or three other occurrences of the same issue just about to be brought to my attention.  Maybe it just seems that way because once I’m on track to discovering the issue I notice other occurrences of the same issue more easily.  All I know is that this happens all the time.

Recently one such issue came to my attention quite a few times and it needs to be talked about.  Any of the following questions were used by those facing the issue:

  • Why doesn’t this command work in that PowerShell console?
  • Why did my PowerShell script work when I ran it here but it doesn’t work when I run it there?
  • Why can’t I find command commandName?  It worked fine when I used it in the other console.
  • I used to be able to use drive driveName, but I can’t anymore.  Why?

The answer to these questions lies in the recognition of one area where PowerShell is not very consistent: through the use of customized PowerShell consoles.

Since PowerShell has been out now for over a year, many product teams now provide PowerShell snapins for their products.  This includes Microsoft products like Exchange, System Center Operations Manager, System Center Virtual Machine Manager, SQL Server and IIS (among others) as well as ISV products like VMware ESX and Server (the VI toolkit) and Quest ActiveRoles Server (the QAD cmdlets).  And there are others who provide PowerShell snapins for a particular business need, like SDM Software’s Group Policy Management Console (GPMC) Cmdlets, /n software’s NetCmdlets, and SoftwareFx’s PowerGadgets.  Many (the majority, in fact) of these snapins come with their own customized PowerShell console.  These customized console are designed to do one or more of the following:

  1. Display welcome text with help.
  2. Show a tip of the day.
  3. Run in elevated mode on Windows Vista and Windows Server 2008.
  4. Load the PowerShell snapin(s) relevant to the product that the shell customization came with.
  5. Change the current location to a provider that was included with the snapin(s) or a drive that was created within the customized shell.
  6. Create custom commands (functions and aliases) to make it easier to use the snapin(s).
  7. Prompt the user for connection-related information to establish a connection required for the cmdlets to work.

There are definitely other possibilities of how these customized consoles might be used, but this list gives you the general idea.  Most of these customizations are helpful because it gives the PowerShell newcomer a starting point; however, more than half of them can give users the wrong impression and cause them to ask the questions listed above when they use other PowerShell consoles.  Let’s look at some examples.

One thing in common among each of the customized consoles is that they load the PowerShell snapin(s) relevant to the product that the shell customization came with.  The Exchange Management Shell loads the two snapins that come with Exchange, so that users don’t have to do this to use Exchange cmdlets:

Add-PSSnapin -Name `
Microsoft.Exchange.Management.PowerShell.Admin
Add-PSSnapin -Name `
Microsoft.Exchange.Management.PowerShell.Support

This might not seem like a big issue, however in practice it seems to give users the false impression that they can simply call the cmdlets they need from any PowerShell script or console, which ultimately results in head-scratching when commands or a script don’t work somewhere else.  And as indicated, this is common among each of the customized consoles, so the IIS PowerShell Management Console, System Center Operations Manager Command Shell, Windows PowerShell with PowerGadgets, and others all do the same thing, loading their respective snapin automatically.

Another customization that seems to be common is for consoles to provide custom commands (aliases and functions) that are only available in that particular console.  VMware does this in their VMware VI Toolkit (for Windows).  When you open that console, you are presented with a message that shows you four commands as useful starting points, three of which only work in the VMware VI Toolkit (for Windows) shell (FYI, the commands I’m referring to are Get-VICommand, Get-VC and Get-ESX).  You can imagine that causes confusion when someone is trying to use one of these commands in another console.  Of course VMware isn’t the only one that does this.  The Exchange Management Shell creates three commands that are only available by default in that console (Get-ExCommand, quickref and Get-ExBlog) and the System Center Operations Manager Command Shell creates 10 commands that are only available by default in that console.  I won’t bother listing all of those here because I’m sure you get the picture by now.  Trying to use these commands in other consoles without adding them to the profile or explicitly creating them results in an error indicating that the command was not found and invariably some head scratching for the individual who is trying to run then.

A third type of customization is to check for the presence of a connection and then to prompt users for connection information if a local connection was not detected.  The System Center Operations Manager 2007 Command Shell provides connection management like this in its console.  The connection that is established is not usable outside of that console, nor is it documented accordingly, so users need to be aware that their scripts will have to include commands to make the required connections in order to work in any PowerShell environment.

There are surely going to be other examples of this as different teams customize their console environment to meet their needs.  As a PowerShell end user, when these customized consoles are very convenient, what can we do to make sure we’re aware of what customizations are being made?

Fortunately the console customizations are easy to discover.  Every customized console uses PowerShell’s command line parameters to perform the customizations.  This means viewing the properties of any of the shortcuts used to launch a customized console allows you to see what customizations are being performed by examining the command line parameters for powershell.exe.  The customizations that you need to look at are the PowerShell console file that is used (as identified by the -psconsolefile argument) and the script that is executed (as identified by the -command argument).  The PowerShell console file (psc1 file) is an xml document that defines which snapins should be automatically loaded by PowerShell when it starts.  The snapins identified in this file are silently added to the PowerShell session when it is opened.  The command argument identifies the PowerShell script or PS1 file that will be run after the snapins are loaded.  This script is used to customize the look of the console, create custom commands, manage connections, etc.

Now that you have this information, all you need to do is make sure you are aware of the customizations in the console you are using, particularly those that are not portable to other consoles, so that you don’t make incorrect assumptions when you write your scripts.

Before I close this off, I have a request that I’d like to put out there for snapin developers.  If you’re creating a customized PowerShell console when your snapin is installed, please make an effort to make those customizations self documenting.  I don’t want you to hurt the end user experience your after, but I think a bit of carefully worded output that identifies your console customizations as customizations that are specific to that console would go a long way to educate beginner PowerShell users about how consoles can be customized and what they need to be aware of when switching from one console to the next.  Without that information, users simply aren’t getting the information that they need to use your commands in other console that they might use.  And of course, if you are making custom function that are only available in your customized console, ask yourself, should those function only be available in one console, or should they be available all the time.  Often times I bet the answer is the latter, so please consider making cmdlets for those function you feel are necessary for the right experience when using your snapin.  Otherwise you’re just making it more difficult for your users to have the experience that you want them to have.

Thanks for reading!

Kirk out.

Share this post:

Public beta of Quest AD cmdlets v1.1 now available

Quest Software (my employer, for the record) has just released the first public beta build of version 1.1 of the ActiveRoles Management Shell for Active Directory (aka Quest AD cmdlets).  If you haven’t looked at these cmdlets yet, they fulfill the scripting needs of AD administrators using PowerShell today by providing them with cmdlets to facilitate management of Active Directory.

You’ll quickly notice once you download the beta that the Quest AD cmdlet team has been hard at work too, with 40 cmdlets available in this beta, now including support for security and permission management!  More fun commands to play with!

If you want to download the latest beta, you can find it here.  And feedback is welcome and appreciated on the PowerGUI community site in the AD forums.

Kirk out.

Share this post :

Learn about PowerGUI on .NET Rocks!, dnrTV and RunAs Radio

During the past two weeks I’ve had the pleasure of sitting down and chatting with Carl Franklin, Richard Campbell and Greg Hughes of .NET Rocks!, RunAs Radio and dnrTV fame about PowerShell, PowerGUI and the Quest AD Cmdlets.  For those of you who don’t know, .NET Rocks! is an internet audio talk show about .NET and dnrTV is the equivalent in an internet screencast format.  Both of these are targeted at the .NET developer.  RunAs Radio is an internet audio talk show for IT professionals who work with Microsoft products.

I didn’t know what to expect from any of these interviews, but fortunately Carl, Richard and Greg are real pros at this and it was a real treat to chat with them.  I believe the end result is much better than what you get from the typical webcast or screencast because they ask the right questions and great conversation comes out as a result.

I was planning on blogging about this before any of these were posted, but these guys are really on top of things and to my surprise this morning I found out that Carl already posted the recording from dnrTV, so you can watch the episode #99 now.  It is simply called “Kirk Munro on PowerGUI”, and can be found here.  The .NET Rocks! and RunAs Radio sessions are not posted yet, but they should be later this week.  I’ll post an update once they are available.

Whether you’re interested in PowerGUI, PowerShell, .NET or working with Microsoft products in general, I encourage you to watch dnrTV and listen to RunAs Radio and .NET Rocks!  What a great way to spend your morning and evening commute in the subway, on the bus, or in your car (although please don’t watch dnrTV while driving your car…that’s just not a good idea; no matter how much you want to learn what PowerGUI and PowerShell can do for you, they won’t fix your car).

Thanks again to Carl and Richard for getting in touch with me and setting this up!  It’s been a great experience!

Lastly, if you’re interested in listening to a bi-weekly podcast that is specifically about PowerShell, you should also check out the PowerScripting Podcast.  The PowerScripting Podcast is hosted by Jonathan Walz and Hal Rottenberg and if you’re into all things PowerShell like I am, this gives you one more way to stay informed about PowerShell during the daily commute.

Thanks for listening!

Kirk out.

Technorati Tags: , , , , , , ,

Quest AD Cmdlets gone gold!

It’s official!

The Quest AD Cmdlets are now RTM!  And they’re still 100% free!  If you are doing any scripting with Active Directory and PowerShell, these cmdlets are absolutely indispensable.

You can download the RTM version here.

Note: The initial post of the RTM version still had “ReleaseCandidate” as part of the msi filename.  This is still the RTM release.  The filename will be corrected shortly.

Kirk out.

Technorati Tags: , , ,

Sometimes you just want a property

On the PowerShell newsgroup I often (really often) see users new to PowerShell getting stuck transitioning from the point where they have a set of objects to creating an array of the values of one of the properties on those objects.  For example, if you are using the free Quest AD cmdlets and you want to retrieve a list of group names to which a member belongs, you can do this:

(Get-QADUser “Poshoholic”).memberOf | Get-QADGroup | ForEach-Object {$_.Name}

This seems simple enough but many people get stuck going from a collection such as that returned by Get-QADGroup to an array of names such as that returned by the ForEach-Object cmdlet shown in this exanple.  The missing piece of knowledge is usually understanding how to use ForEach-Object to extract the member you want.  Also, even when you know how to use ForEach-Object, I find it a little inconvenient to use ForEach-Object with a script block just to pull out a property name, or to put brackets around part of a command so that I can access members on the result.  And I find myself doing this quite regularly in my PowerShell work.

To both save myself from having to use ForEach-Object or brackets when all I want is to invoke a member on an individual object or a collection of objects, and to share this convenience with others, I have created an Invoke-Member function that makes the one-liner I listed above a little more elegant and PowerShelly.  Here’s an updated version of the one-liner I used above, revised to use the Invoke-Member function:

Get-QADUser “Poshoholic” | Invoke-Member memberOf | Get-QADGroup | Invoke-Member name

This one-liner retrieves an AD user named Poshoholic and from that user it retrieves the memberOf member value.  That value contains an array of DNs for groups to which the user belongs.  For each of those DNs, the one-liner then retrieves the AD group object and once it has that it extracts the name of that group.

The Invoke-Member function can be used to invoke any type of member, including both properties and methods (e.g. Invoke-Member “Open()”).  It can also be used to invoke nested members (e.g. Invoke-Member parameters.parameter).  And it can take input from the pipeline or alternatively through the InputObject parameter.  When using the InputObject parameter, the object is passed in as one object, even if it is a collection.  When using the pipeline collections are passed into Invoke-Member one item at a time.

[Update] Since this was originally posted, Xaegr pointed out in the comments that the PowerShell team already had published a function on their blog that does this, and that he has modified that function to support multiple members.  You can find that blog entry here, and Xaegr’s modifications can be found in the comments in this blog entry.  The problem with those two implementations of the … function  is that they don’t support calling methods and they don’t support nesting members, both of which are supported by the Invoke-Member function.  I liked Xaegr’s idea to support retrieving multiple members at once though, which I think could be useful for simplified output of member values without member names attached to that output.  I also think it would be useful when working with certain datasets that have different members with the same type that you want to do something with in one pass through that data set, or when you want to execute multiple methods in sequence during one pass through a dataset.  I added support to the Invoke-Member function so that it would support multiple members as well.

Here is the updated source code for the Invoke-Member function as well as a script to create im and … aliases for the Invoke-Member function:

Function Invoke-Member {
    param (
        [string[]]
$name = $(throw $($(Get-PSResourceString -BaseName ‘ParameterBinderStrings’ -ResourceId ‘ParameterArgumentValidationErrorNullNotAllowed’) -f $null,‘Name’)),
       
$inputObject = $null
   
)
    BEGIN {
    }
    PROCESS {
       
if ($inputObject -and $_) {
           
throw $(Get-PSResourceString -BaseName ‘ParameterBinderStrings’ -ResourceId ‘AmbiguousParameterSet’)
           
break
        } elseif ($inputObject) {
            foreach ($member in $name) {
               
Invoke-Expression “`$inputObject.$member”
           
}
        }
elseif ($_) {
           
foreach ($member in $name) {
               
Invoke-Expression “`$_.$member”
           
}
        } else {
           
throw $(Get-PSResourceString -BaseName ‘ParameterBinderStrings’ -ResourceId ‘InputObjectNotBound’)
        }
    }
    END {
    }
}
if (-not (Get-Alias -Name im -ErrorAction SilentlyContinue)) {
    New-Alias -Name im -Value Invoke-Member -Description ‘Invokes a member of each of a set of input objects.’
}
if (-not (Get-Alias -Name-ErrorAction SilentlyContinue)) {
    New-Alias -Name … -Value Invoke-Member -Description ‘Invokes a member of each of a set of input objects.’
}

Note that this function uses the Get-PSResourceString function that I published recently in my Cmdlet Extension Library (you can read more about what this library contains here).  If you want to use the Invoke-Member function by itself, you will have to change the calls to Get-PSResourceString with static strings that you want to throw on error instead.  To simplify sharing the Invoke-Member function with the community I have added it to my Cmdlet Extension Library and uploaded the updated version to the PowerShell Community site.

Thanks to Joel Bennett for his article about writing functions that can also be executed in the pipeline.  I didn’t end up using Joel’s template as is because I wanted Invoke-Member to follow the model of other cmdlets that have the InputObject parameter, but it was my starting point before I went through numerous revisions and ended up with the final version shown above in the Invoke-Member function code.

Comments/suggestions are welcome and appreciated, as always.

Kirk out.

Technorati Tags: , , , , ,