New Book Project – Reviewers Needed

While at Microsoft TechEd, I signed the paperwork to write a second edition of Managing Active Directory with Windows PowerShell: TFM for SAPIEN Press. It’s hard to believe so much has happened since that book hit the shelves in less than 2 years. The 2nd edition will continue to include coverage of Quest Software’s PowerShell comdlets (naturally updated and expanded where necessary). Almost all of the ADSI content will be dropped and I’ll be explaining how to use the Microsoft ActiveDirectory provider and cmdlets. My goal is to write a book that is really two books in one.

To that end I’ll be in need of some rock-solid and reliable technical reviewers. I need 4-5 people who will have time and resources over the next 4-6 months to read manuscripts, test out code samples and provide constructive feedback. Ideally, a reviewer should be able to run the Quest cmdlets and the Microsoft cmdlets with either a Windows Server 2008 R2 domain controller or the Active Directory Management Gateway Service. Please DO NOT use your production environment. You will need to test from a Windows 7 desktop. It would be helpful to have reviewers from a variety of organizations from small 100 user companies to 10,000 plus.  Selected reviewers will receive a free printed copy of the final book and a $50 gift card (not to mention my grateful thanks and the admiration of your peers).

If you are interested, send me an email (jhicks@jdhitsolutions.com). Tell me about your PowerShell background, the scope of your Active Directory environment that you can test with and anything else you think I should know. If you are selected, you’ll get an email from me. If you aren’t selected, you’ll go on my list of alternate reviewers should people drop out early in the process.

I’m looking forward to the project and trust you will be as well.

Get Chitika Premium

Post to Twitter Post to Delicious Post to Facebook Post to StumbleUpon

Posted in Books, PowerShell v2.0, Quest Software, SAPIEN Press, Scripting, Windows 7, Windows Server | Tagged , , , , , | 2 Comments

TechEd 2010 VBScript to PowerShell

Last week I posted my demo slides as well as my demo videos. As promised, I’ve gone through and expanded a bit on my original slide deck.  TechEdNA-2010-Hicks-ParadigmShift is a 3MB PDF of my expanded PowerPoint slide deck. If you have any questions about the content or what it takes to get your head from the world of VBScript to Windows PowerShell, please let me know.  I hope you find this useful. Enjoy.

Post to Twitter Post to Delicious Post to Facebook Post to StumbleUpon

Posted in Conferences, PowerShell v2.0, Scripting, TechEd, WMI | Tagged , , | Leave a comment

TechEd 2010 Demos

As promised,  I’ve assembled my demo scripts as well as the transcriptfrom my TechEd 2010 talk Paradigm Shift Microsoft Visual Basic Scripting Edition to Windows PowerShell. The official slide deck is supposed to be available on the TechEd web site.  I’m going to post an expanded version of the deck here sometime next week.

In the meantime, this zip file has all of the demo scripts I used. I also made backup videos of my demos using Camtasia. If you are interested, you can download a zip file with all of them.

Post to Twitter Post to Delicious Post to Facebook Post to StumbleUpon

Posted in Best Practices, Conferences, PowerShell, PowerShell v2.0, Training | Tagged , | 4 Comments

Microsoft Deployment Toolkit PowerShell Wizard

During the last TechMentor conference in Orlando, deployment MVP and guru (I want to call her a deployment diva but I don’t want people to get the wrong idea. Think “diva” in the star sense without the ego and entourage,) Rhonda Layfield asked me to look at some PowerShell code. She was trying to make sense of code cobbled together from the Microsoft Deployment Toolkit to create a deployment share. I’m not much on deployment technologies these days (I miss the RIS days), but PowerShell I know.

Eventually we ended up with a more coherent and usable script. Of course, since I’m always looking for something extra, I thought this would make a great basis for a WinForms script. There are a lot of pieces to this puzzle so a form-based wizard seemed like a good idea. The end result is DeploymentWizard.ps1.

deploymentwizard-2

If you are familiar with the deployment toolkit then I expect you’ll know how to fill in the blanks. If not, I’ve used a ToolTip control in the form to provide popup help when you hover your mouse over a field.

After you complete the form, click Build It and the deployment share will be created along with the task sequence. All of the MDT cmdlets are executed using –verbose so you can keep track. Expect the script to need several minutes to complete. When finished, you should see a new share in the MDT management console.

deploymentworkbench

The only caveat is that you need to run the script in an elevated session. If you have deployment questions or needs, I encourage you to contact Rhonda via her web site, http://www.deploymentdr.com. The official name is “Deployment Done Right”, but I also look at the link as “deployment doctor” which works just as well.

If you have PowerShell-related problems with the script, let me know. I have limited resources for testing so I can’t guarantee you won’t run into something.

I used SAPIEN’s PrimalForms 2009 to develop the form and script. The source PFF file is included in the download zip file if you are interested in modifying the form. Otherwise, edit the PS1 file as necessary.

Let me know how this works out for you.

Post to Twitter Post to Delicious Post to Facebook Post to StumbleUpon

Posted in PowerShell v2.0, PrimalForms, Scripting, Windows 7, Windows Server | Tagged , , , , | 2 Comments

Microsoft TechEd NOLA

Print I’m very excited about Microsoft TechEd next week in New Orleans, LA. I’ll be presenting Tuesday afternoon at 1:30PM. The official title is “Paradigm Shift: Microsoft Visual Basic Scripting Edition to Windows PowerShell”. In more practical terms, I’ll be talking about the necessary mind shift in moving from VBScript to PowerShell. I’ll talk about what you have to get your head around to successfully make the transition and provide some practical examples to demonstrate how you might make these changes. As with many of my talks, you can expect a lot of demos.

Other than that, I’ll be in the Windows Server booth (TLC/Red/WSV) throughout the week.

Monday, June 7 10:30 AM – 12:30 PM

Tuesday, June 8 10:30 AM – 12:30 PM, 2:45 PM – 5:00 PM

Wednesday, June 9 10:30 AM – 3:00 PM

Thursday, June 10 12:15 PM – 3:00 PM

I hope you’ll come by and at least say Hi. Or feel free to pick my brain.  If you have books you’d like signed, I’m happy to do that as well. I’ll be pretty active with FourSquare and Twitter if none of these times work for you.

See you next week.

Laissez les bon temps rouler!

Post to Twitter Post to Delicious Post to Facebook Post to StumbleUpon

Posted in Conferences, PowerShell v2.0 | Tagged , , , | 4 Comments

Get Parent Process

parent-child Recently I helping out on a post in the forums at ScriptingAnswers.com. The question centered around identifying processes on a computer and their parent process. There are many ways you could slice and dice this problem using WMI and Get-WmiObject. Getting the parent process ID is pretty simple, but going backwards from there to identify the parent process takes a little PowerShell jujitsu.

Because I love objects (geeky, I know), one angle I pursued created a custom object for each parent process. The object included a few key (at least to me) properties as well as a property that held an array of all child processes.

Here’s an example.

ParentID          : 916
Children          : {@{ProcessID=4068; ProcessName=Moe.exe; Description=Moe.exe
; Created=5/19/2010 8:52:59 AM}, @{ProcessID=4716; ProcessN
ame=SkypeNames2.exe; Description=SkypeNames2.exe; Created=5
/20/2010 8:13:47 AM}, @{ProcessID=1600; ProcessName=VBoxSVC
.exe; Description=VBoxSVC.exe; Created=5/20/2010 11:59:31 A
M}, @{ProcessID=6828; ProcessName=WmiPrvSE.exe; Description
=WmiPrvSE.exe; Created=5/21/2010 7:57:22 AM}}
NumberofChildren  : 4
ParentCreated     : 5/19/2010 8:51:46 AM
ParentProcess     : svchost.exe
Computername      : SERENITY

To get here, I called a function I wrote called Get-ParentProcess.

function Get-ParentProcess {
    #requires -version 2.0                       

    [cmdletBinding()]            

    Param(
        [Parameter(Position=0,ValueFromPipeline=$True,
                   HelpMessage="Enter a computername")]
        [string[]]$computername=$env:computername)            

    Begin {
      write-verbose "Starting $($myinvocation.mycommand)"
      #capture some performance metrics
      $start=Get-Date
      $total=0
    }
    Process {                
foreach ($computer in $computername) {
        Write-Verbose "Testing $computer"
        if (Test-Connection -ComputerName $computer -quiet) {
            #only process if ping returns true
            Write-Verbose "Connecting to $computer"            

            Get-WmiObject -Class win32_process -ComputerName $computer `
            -outvariable data |
            Sort-Object -Property ParentProcessID |
            Group-Object -Property ParentProcessID  | foreach {            

             $ParentID=$_.Name
             $ParentProcess=$data | where {$_.processID -eq $parentID}
             if (-not $parentProcess) {
                write-verbose "nothing found for $parentID"
             }            

             Write-Verbose "Parent process $($parentProcess.name)"            

             #convert creationdate to a friendly format if found
             if ($parentProcess.CreationDate) {
               $ParentCreation=`
           $ParentProcess.ConvertToDateTime($parentProcess.CreationDate)
             }
             else {
               $ParentCreation=$null
             }
             #use computername from process object if it exists, 
             #otherwise use the value from $computer
             if ($parentProcess.CSName) {
               $ParentComputerName=$parentProcess.CSName
             }
             else {
                $ParentComputerName=$computer
             }            

             $NumberChildren=$_.group.count
             Write-Verbose "Found $NumberChildren child process(es)"
             $Children=$_.group |
              Select -property ProcessID,ProcessName,`
              @{Name="Created";
              Expression={$_.ConvertToDateTime($_.CreationDate)}}            

             Write-Verbose "Creating custom object"
             New-Object PSObject -Property @{
                Computername=$ParentComputerName
                ParentID=$ParentID
                ParentProcess=$ParentProcess.Name
                ParentCreated=$ParentCreation
                NumberofChildren=$NumberChildren
                Children=$Children
             }
           } #end foreach
      } #end if Test-Connection
      else {
        Write-Warning "Failed to connect to $computer"
      }
       $total+=$data.count
   } #end foreach $computer

}#Process
End {

$finish=Get-Date

     $msg="Processed {0} processes from {1} computers in {2}" -f `
        $total,$computername.count,($finish-$start)
     write-verbose $msg
       write-verbose "Ending $($myinvocation.mycommand)"
   }
} #end Function

This is an advanced function so it requires PowerShell 2.0. The actual function includes comment based help. I’ve omitted here.

The function takes a computername as a parameter, defaulting to the local computer. You can pipe names to the function as well. Here’s what happens when you connect to the remote computer using Get-WmiObject.  The collection of Win32_Process objects is sorted by the ParentProcessID and then piped to Group-Object. This created a GroupInfo object. The name property is the parent process ID and the corresponding group are all the child processes.

Each group is then parsed and processed pulling out process information and defining new properties. To get the parent process name I search the saved WMI results looking for a process id that matches the parent process ID I’m checking. If you look back at the Get-WmiObject expression you’ll see I’m taking advantage of the –OutVariable common parameter. The cmdlet’s result is not only passed down the pipeline but also stored in the variable. In this case, $data. When you use –OutVariable just specify the variable name you want to use. You don’t need the $.

For the child processes that are in the group I select a few key properties. $Children will be a collection of custom process objects. This value is used as a property value, among others, in New-Object.

When you run the function, you most likely will notice some parent processes with no name. More than likely this is because the parent process is no longer running.

PS C:\> $r=get-parentprocess

PS C:\Scripts> $r | where {-not $_.parentProcess} | select-object -ExpandProperty Children | Sort Created | format-table –autosize

ProcessID ProcessName               Created
——— ———–               ——-
596 csrss.exe                 5/19/2010 8:51:43 AM

676 wininit.exe               5/19/2010 8:51:44 AM

696 csrss.exe                 5/19/2010 8:51:44 AM

852 winlogon.exe              5/19/2010 8:51:45 AM

3396 explorer.exe              5/19/2010 8:52:39 AM

3988 ToshibaServiceStation.exe 5/19/2010 8:53:07 AM

3564 TWebCamera.exe            5/19/2010 8:53:12 AM

3792 TUSBSleepChargeSrv.exe    5/19/2010 8:53:12 AM

2208 VCDDaemon.exe             5/19/2010 8:53:12 AM

4112 jusched.exe               5/19/2010 8:53:13 AM

4164 vmware-tray.exe           5/19/2010 8:53:14 AM

3656 SWin.exe                  5/19/2010 9:03:57 AM

Even if you don’t have a use for the function, I hope you find some useful scripting techniques.

Update: I’ve been using the PowerShell ISE to create the script files on an x64 platform. The Unicode default can be problematic.  Here is an ANSI version of the file.  I’ll try to remember to stick to ANSI from now on.

Post to Twitter Post to Delicious Post to Facebook Post to StumbleUpon

Posted in PowerShell v2.0, Scripting, WMI | Tagged , , , , , , | 3 Comments

New WMI Object

I have one more variation on my recent theme of working with WMI objects. I wanted to come up with something flexible and re-usable where you could specify a WMI class and some properties and get a custom object with all the classes combined. My solution is a function called New-WmiObject.

Function New-WMIObject {            

[cmdletbinding()]            

Param (
      [Parameter(Position=0,ValueFromPipeline=$True,
      HelpMessage="Enter a computername.")]
      [string[]]$computername=$env:computername,
      [Parameter(Position=1,ValueFromPipeline=$False,
      HelpMessage="Enter a hashtable of WMI classes and properties.",
      Mandatory=$True)]
      [hashtable]$hashtable
)            

Begin {
     write-verbose "Starting $($myinvocation.mycommand)"
}#begin            

Process {
 foreach ($computer in $computername) {
 #initialize property hash
     $properties=@{}
     write-verbose "Adding $($computer.toUpper()) to `$properties"
     $properties.Add("Computer",$($computer.toUpper()))
    foreach ($hash in $hashtable) {
        $classes=$hash.keys
        foreach ($class in $classes) {
            write-verbose "Getting $class information on $computer"
            $wmi=Get-WmiObject -Class $class -Property $hash.item($class) `
            -computername $computer
            #create array properties if $wmi returned more than one item
            if ($wmi.count -gt 1) {
                write-verbose "Multiple WMI objects returned"
                #initialize a temporary array
                $array=@()
                foreach ($object in $wmi) {
                    Write-Verbose "Adding $($object.__RELPATH)"
                    $array+=$object | select $hash.item($class)
                }#end foreach $object
                #add the array as a property value
                #strip off win32_ from the class name
                $parsed=$class.Substring($class.indexof("_")+1)
                $properties.Add($parsed,$array)
            }
            else {
                #add each property
                    foreach ($item in $hash.item($class)) {
                    write-verbose "Adding $item = $($wmi.($item))"
                    $properties.Add($item,$($wmi.($item)))
            }
            } #else
        } #foreach $class            

    } #foreach $hash
    Write-Verbose "Creating custom object"
    New-Object PSObject -Property $properties
 } #foreach $computer
} #process            

End {            

 write-verbose "Ending $($myinvocation.mycommand)"
} #end
} #end function

The function takes a computername as either a direct or pipelined value. The default is the local computer. The other value is a hashtable of WMI information. The key is the name of a Win32 WMI class. The value is a comma separated list of properties for that particular class. The function will gather the requested WMI information and write a custom object to the pipeline with each property. This means that you are limited to unique property names in your hashtable. If you have two classes you want to query, each with a property of Version, the function can’t return both values. If someone would like to revise the script to accommodate this that would be great.

The function works best if the WMI classes return single instances. If the WMI class you want to query will return multiple instances, New-WmiObject will work but it will return a property that contains an array of the objects. For example. here’s a hash table I want to use:

$a=@{win32_OperatingSystem="Caption","RegisteredUser","LastBootUpTime";
win32_computersystem="Name","Manufacturer","Model";
win32_bios="Version";
win32_logicaldisk="deviceid","size","freespace","drivetype"}

After loading the function into my shell I can run it like this:

PS C:\> new-wmiobject –hashtable $a

RegisteredUser : Jeff

Version        : TOSQCI – 6040000

Model          : Qosmio X505

LastBootUpTime : 20100514111336.610798-240

Name           : SERENITY

logicaldisk    : {@{deviceid=C:; size=487439986688; freespace=276030799872; dri

                 vetype=3}, @{deviceid=D:; size=; freespace=; drivetype=5}, @{d

                 eviceid=E:; size=1000202039296; freespace=504326586368; drivet

                 ype=3}, @{deviceid=F:; size=; freespace=; drivetype=5}…}

Manufacturer   : TOSHIBA

Caption        : Microsoft Windows 7 Ultimate

Computer       : SERENITY

Notice the Win32_logicaldisk entry from the hashtable is used to define a property name for the collection by stripping off WIn32_. Working with individual properties of the custom object should be pretty straightforward.

PS C:\> $r | format-table Computer,Caption,Model -AutoSize

Computer Caption                       Model                          
——– ——-                       —–                          
GODOT7   Microsoft Windows 7 Ultimate  Latitude D800                  
SERENITY Microsoft Windows 7 Ultimate  Qosmio X505  

If you want to work with the array properties, like logicaldisk in my example, you could try an expression like this:

PS C:\Scripts> $r | select-object -property computer -expand logicaldisk |

where {$_.drivetype -eq 3} | format-table -GroupBy Computer -Property DeviceID,Size,FreeSpace

   Computer: GODOT7

DeviceId                                         Size                 FreeSpace

——–                                         —-                 ———

C:                                       119926681600               45238063104

   Computer: SERENITY

DeviceId                                         Size                 FreeSpace

——–                                         —-                 ———

C:                                       487439986688              276032737280

E:                                      1000202039296              504326586368

J:                                       320070287360               91348078592

I think this function will work just fine as long as you stick to a few classes that return single instances and if you can limit yourself to unique WMI property names. The function has plenty of room for improvement as it is lacking comment based help, support for alternate credentials, and error handling. If you work up a new version I’d be happy to post it.

Post to Twitter Post to Delicious Post to Facebook Post to StumbleUpon

Posted in PowerShell, WMI | Tagged , , , , | Comments Off