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:

Use PowerShell instead of cmd.exe

If you’re reading this blog then the point is probably moot, but I’ll put it out there anyway.  One strong recommendation I was giving to IT admins who came to see me on the tour I was on for the past three weeks was this: if you need to go into cmd.exe to run some command, do it in PowerShell instead.  This is really, really important.  Jeffrey Snover talks about it here.  Even if you don’t have time to dive in and start learning a lot about it today, just using PowerShell instead of cmd.exe is a step in the right direction.  It will start exposing you to how things work slightly differently in PowerShell and allow you to start scratching the surface so that learning more is just that much easier when you do have the time to do so.  The next time you find yourself in cmd.exe, flip over to PowerShell and run your commands there instead!  You’ll be doing yourself a big favour!

Kirk out.

Technorati Tags: ,,

Share this:

EnergizeIT Certification Bootcamp – National User Group Tour 2008

Last night marked the last stop for the EnergizeIT Certification Bootcamp National User Group Tour 2008 here in Canada.  A little while back Microsoft invited me to present Windows Server 2008 features (including PowerShell) during this tour with Kai Axford, and I am absolutely thrilled that I was able to take them up on their offer.  Kai is a phenomenal speaker and it was a great privilege for me to be able to present at these events with him.

The tour spanned across the last three weeks and included 10 major cities in Canada, in the following order: Halifax, Toronto, Ottawa, Montréal, Winnipeg, Regina, Victoria, Vancouver, Calgary and Edmonton.  Previously I had only been to the first four of these cities, so this was a great opportunity for me to get out and visit the rest of Canada.  There was a ton of interest in this tour and most stops sold out within 24 hours after they were announced.  Fortunately there were not many technical difficulties along the way at all, and for those technical difficulties that did occur, I sincerely apologize for the impact they had on the demonstrations.

One thing in common among each of these events that really made it fun for me as a presenter was the people.  The people that took the time to come out and try and learn something from these events were just great.  I can’t tell you how much I enjoyed being able to meet so many IT professionals face to face, hear about their problems or concerns, and hopefully show them something useful that will make their job easier.

Many thanks to Kai, Sim, Bruce, Nik, the user group leads, all of the attendees for coming out, and anyone else involved in making this event happen!  It has been a very rewarding experience for me!

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:

How to navigate in a PowerShell provider without a PSDrive

Here’s an interesting PowerShell trick that I hadn’t come across before.  I may be mistaken, but I don’t believe this is documented anywhere either.

In PowerShell, you can create PowerShell drives (PSDrives) to provide you with fast access to specific locations in the PowerShell providers that you are using.  That is very convenient, but if you are writing scripts that use the drives you create and that you share with others, you need to make sure the PSDrive is created for your script to work.  Or do you?

In PowerShell, you can set the current location to any location on a provider using the following syntax:

Set-Location PSDriveName:RelativePath

In this syntax, RelativePath refers to the path relative to the root of the PSDrive identified by PSDriveName.

Alternatively, you can also set the current location to any location on a provider using the following syntax:

Set-Location PSProviderName::AbsolutePath

In this syntax, AbsolutePath refers to the absolute path to the location on the respective drive (which includes the root if necessary) and PSProviderName refers to the name of the provider, with or without the PowerShell snapin name prefix.

Let’s look at a few specific examples.

If you wanted to set the current location to C:\Windows, you could do any of the following:

  1. Set-Location C:\Windows
  2. Set-Location FileSystem::C:\Windows
  3. Set-Location `
       Microsoft.PowerShell.Core\FileSystem::C:\Windows

How about the registry?  Lets say you wanted to browse HKEY_USERS in your registry so that you could work with the default user configuration.  To do this, you would have to do any of the following:

  1. New-PSDrive HKU Registry HKEY_USERS
    Set-Location HKU:\.DEFAULT
  2. Set-Location Registry::HKEY_USERS\.Default
  3. Set-Location `
       Microsoft.PowerShell.Core\Registry::HKEY_USERS\.Default

What if you wanted to view the root of the registry?  I have no idea how to do that using a PSDrive, but you can do it using the provider path like this:

Set-Location Registry::

The syntax looks a little unusual, but it can be useful.  Executing Get-ChildItem from there gives you all of the hives that are available in the registry.  If you want to do a search across an entire registry, this seems to be the right place to start.

So far all of these examples have been for the providers that are included in the PowerShell 1.0 RTM release.  But the syntax described above works for providers from registered snapins as well.  Using the IIS 7.0 PowerShell Provider Tech Preview 1 we can do the same sort of thing.  For example, I can browse the application pools like this:

Set-Location `
  
WebAdministration::\\POSHOHOLIC\AppPools

Note that in this example, POSHOHOLIC is the name of the computer (and it must be in uppercase for it to work in Tech Preview 1 of this provider).  And yes, I could have used IIsProviderSnapin\WebAdministration for the provider name here as well.

One last example from a registered snapin is from the SQL Server 2008 CTP.  You can navigate to the root of this provider like this:

Set-Location SqlServer::SQLSERVER:

This puts you in the same location as if you set the location to SQLSERVER:.  Note again, in this example, the second SQLSERVER must be in uppercase for it to work in the February 2008 CTP version of this provider.  And the syntax here is a little odd as well…the second SQLSERVER really shouldn’t be necessary IMHO.  But it’s there, so we have to use it.

I should also mention that these provider-based paths should work wherever you can use a path.  I tested out a few of them and was satisfied enough to feel confident that the paths will work anywhere.

By now you most likely get the idea of this.  You can continue to write your scripts to create PSDrives and access everything by drive name, or you can work directly with the provider-based paths so that you don’t have to create PSDrives and so that you can access provider roots that are otherwise unavailable.

Kirk out.

Share this post:

 

Use PowerGUI to manage SQL Server 2008

SQL Server 2008 marks the first release for SQL Server that includes PowerShell support.  This is just the beginning of a trend for all Microsoft Server products now that PowerShell is part of their Common Engineering Criteria beginning in fiscal year 2009.  I just spent the past week or so experimenting with PowerShell and SQL Server, first using SMO directly and then using the snapins that are part of SQL Server 2008.

I’m still testing the waters in many places but so far I’m pretty happy with the PowerShell support in SQL Server 2008.  Back when they first announced support, it didn’t sound all that impressive but now that I’ve dug in and started using it myself I’ve found that it is much more than I thought it would be.  SQL Server 2008 is still in CTP, so there are still bugs and still changes coming, but overall this looks like a nice addition to PowerShell, and one that should get even better through service packs as time goes on.

While working with the SQL provider and cmdlets I put together my first-attempt at a SQL Server PowerPack for PowerGUI.  This PowerPack is pretty lightweight at this point, allowing you to browse through the SQL Server instances you have, add connections to other servers, open tables and views and view their contents, as well as a few other miscellaneous things.  It requires the SQL Server 2008 client tools, however it seems to work fine with SQL Server 2005 (and presumably SQL Server 2000 since it uses SMO and WMI under the covers) once you have the SQL Server 2008 client tools installed.  You can download the PowerPack here.

Over the next little while I will be continuing to enhance this PowerPack, so if you work with SQL Server and PowerShell and have any feedback or enhancement requests for this PowerPack, please let me know through comments, email (see my about page), or the PowerGUI forums.

Thanks,

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 :

How to create a PowerPack

A little while back Marco Shaw invited me to present at one of the PowerShell Virtual User Group meetings he runs regularly.  I was quite looking forward to presenting, and I was going to demonstrate how you can extend the PowerGUI administration console as well as how you can share these extensions by exporting them in PowerPacks and making them available to the PowerShell community.  Creating PowerPacks is a large part of what I do at work every day, and I get a lot of questions about how to do it, so I was looking forward to being able to answer those questions in my demonstration.

Unfortunately I had some challenges in front of me at the time and I ended up cancelling my presentation (sorry Marco!).  Still, I really wanted to show how PowerGUI can be extended and how PowerPacks are made, so I recently recorded a screencast that contains pretty much everything I was hoping to show off in my presentation.  Are you interested in learning how you can extend PowerGUI and how you can create your own PowerPacks?  You can check out the screencast/tutorial I made here.

Are there other screencasts/tutorials you would like to see for PowerShell and/or PowerGUI?  Let me know.  If comments don’t work for you, you can find my contact information in my about page.

And lastly, are there things you would like to see in the PowerPacks that come with PowerGUI?  Are there PowerPacks that you would like to see that aren’t published yet?  Let me know that as well!

Kirk out.

Share this post :

whence in PowerShell

[Update: Thanks to Joel Bennett for the comments; my original version didn’t account for external scripts and applications having the same precedence, but this revised version does]

Recently a fellow MVP pointed out that PowerShell doesn’t have a whence command readily available.  whence is a command from the Korn Shell.  When a name is provided to the whence command, it returns the way in which that name will be interpreted by the shell.

While PowerShell doesn’t have that functionality out of the box today, you can easily add it with the addition of a simple function to your PowerShell profiles.  Here’s my interpretation of the whence command in a PowerShell function:

function whence {
    param(
        [
string[]]$command,
        [
Switch]$ReturnAll

    )

    # Put any additional arguments in $command
    if ($args.Count -gt 0) {
        $command += [string[]]$args
   
}

    # Read the current path environment variable
    $path = $env:Path.Trim(;).Split(;)

    # Store an array of all command types that have equal
    # precedence
    $equalPrecedence = ExternalScript,Application


    #
Set the command precedence expression for sorting
    $cmdPrecedence = {
        if ($equalPrecedence -contains $_.CommandType) {
            [
Management.Automation.CommandTypes]`
                $equalPrecedence[0]
        }
else {
            $_.CommandType
        }
    }

    # Set the path precedence expression for sorting
    $pathPrecedence = {
        if ($equalPrecedence -contains $_.CommandType) {
            [
Array]::IndexOf(
                $path,
                [
IO.Path]::GetDirectoryName($_.Definition)
            )
+ 1
        }
else {
            1
        }
    }

    # Filter out all but the first command if appropriate
    foreach ($item in $command) {
        if ($ReturnAll) {
            Get-Command -Name $item `
                |
Sort-Object `
                    -Property $cmdPrecedence,$pathPrecedence `
        }
else {
            Get-Command -Name $item `
                |
Sort-Object `
                    -Property $cmdPrecedence,$pathPrecedence `
                |
Select-Object -First 1
        }
    }
}

This function supports retrieving multiple commands at once, whether they are passed in as an array or not.  For example, you can retrieve the commands for Get-Help and Get-Command by calling either of the following:

  1. whence Get-Help,Get-Command
  2. whence Get-Help Get-Command

It also supports retrieving all results for a specific command so that you can determine why the command you want isn’t executing when you try to call it by name.  Here’s an exaggerated example, to illustrate the value here:

PS C:\> whence Get-Help -ReturnAll

CommandType    Name         Definition
———–    —-         ———-
Alias          get-help     get-help
Function       Get-Help     begin {…
Cmdlet         Get-Help     Get-Help [[-Na…
ExternalScript Get-Help.ps1 C:\Get-Help.ps1
Application    get-help.exe C:\get-help.exe

If I had multiple executable applications, such as get-help.exe and get-help.cmd, this would return them in their precedence order.  If I was trying to execute any command here other than the alias, this would help me figure out why it wasn’t executing when I was simply calling get-help.To use this command in your PowerShell environment, simply copy the function into your PowerShell profile and it will be available the next time your profile is run.

Enjoy!

Kirk out.

Technorati Tags: ,,

Share this post :

2008 Scripting Games Statistics

Now that the 2008 Scripting Games are over, I was wondering how the various scripting languages broke down in terms of individual participation.  I contacted fellow MVP Marco Shaw about this a few weeks ago because last year he wrote a script that would generate a nice chart using PowerGadgets showing the breakdown of the 2007 Scripting Games participation by division for each country.  He had been working on running his old script against this year’s results, and was kind enough to let me have his work in progress to experiment with myself (thanks Marco!).

After tweaking the script off and on (more off than on) over the past few weeks I’ve managed to get the results I was looking for.  The following screenshot shows two charts from the results of each of the last two years of the Scripting Games, all generated using PowerGadgets.  The charts on the left show the breakdown of individual participation by country for the top 10 countries (where the top 10 countries are defined by those with the most unique participants across all divisions), sorted alphabetically.  The charts on the right show the number of unique participants in each division.  The 2007 results are on the top, and the 2008 results are on the bottom.

ScriptingGamesStatisticsDashboard

The results are pretty interesting.  Not surprisingly, the charts show that PowerShell is growing in popularity.  Last year there were 1/3 as many participants in the PowerShell categories as in the VBScript categories.  This year that gap has narrowed, with PowerShell participation climbing to just under ½ of the VBScript participation.  The charts also show that there were only two changes in the top 10 participating countries since last year, and that VBScript wasn’t the scripting language of choice in all top 10 countries in either year.

In addition to the charts that are output, my updated version of Marco’s script also outputs some general statistical information for the years that it is being run against.  From this I can see that the number of individual participants has increased from 510 in 2007 to 709 in 2008, with the number of active participants (where an active participant is defined as one that participated in 5 or more events) increasing from 378 in 2007 to 563 in 2008.

The script used to generate these results can be found here.

All in all, the Scripting Games seem to be increasing in popularity year over year which is likely a trend that will continue as PowerShell and other scripting languages continue to gain traction.  It will be interesting to see how things pan out next year!

Kirk out.

Share it:

P.S. One of the many things I was involved in while I wasn’t blogging during the month of February was the 2008 Scripting Games.  A while back Scripting Guy Greg Stemp invited me to be a guest commentator for this years games (thanks Greg!) and I was assigned Advanced Windows PowerShell Event #5.  While I unfortunately didn’t have time to participate in the other events this year, I did find some spare time during a train trip to Toronto so I wrote my solution for the event on the train.  The games are all done for this year, but if you’re interested in my solution, it can be found here.

P.P.S. I’m trying out using Windows Live SkyDrive as the site from which to share ps1 files.  If you have any problem viewing the script file I’ve linked to in this article, please let me know.