PowerShell Quick Tip: Getting all of the members of an object

If you weren’t already aware, using the Get-Member cmdlet is essential to understanding what you can do with PowerShell.  Get-Member allows you to identify the members (properties, methods, events, etc.) that are available on the objects you are working with.  What some people don’t realize with Get-Member however is that by default it does not identify all members that are available on the objects that are passed into it.

For example, let’s take a look at how you might use Get-Member to see what you can do with Win32_BIOS objects, like this:

Get-WmiObject Win32_BIOS | Get-Member

That command yields the following results:

   TypeName: System.Management.ManagementObject#root\cimv2\Win32_BIOS

Name                  MemberType   Definition
—-                  ———-   ———-
BiosCharacteristics   Property     System.UInt16[] BiosCharacteristics {get;set;}
BIOSVersion           Property     System.String[] BIOSVersion {get;set;}
BuildNumber           Property     System.String BuildNumber {get;set;}
Caption               Property     System.String Caption {get;set;}
CodeSet               Property     System.String CodeSet {get;set;}
CurrentLanguage       Property     System.String CurrentLanguage {get;set;}
Description           Property     System.String Description {get;set;}
IdentificationCode    Property     System.String IdentificationCode {get;set;}
InstallableLanguages  Property     System.UInt16 InstallableLanguages {get;set;}
InstallDate           Property     System.String InstallDate {get;set;}
LanguageEdition       Property     System.String LanguageEdition {get;set;}
ListOfLanguages       Property     System.String[] ListOfLanguages {get;set;}
Manufacturer          Property     System.String Manufacturer {get;set;}
Name                  Property     System.String Name {get;set;}
OtherTargetOS         Property     System.String OtherTargetOS {get;set;}
PrimaryBIOS           Property     System.Boolean PrimaryBIOS {get;set;}
ReleaseDate           Property     System.String ReleaseDate {get;set;}
SerialNumber          Property     System.String SerialNumber {get;set;}
SMBIOSBIOSVersion     Property     System.String SMBIOSBIOSVersion {get;set;}
SMBIOSMajorVersion    Property     System.UInt16 SMBIOSMajorVersion {get;set;}
SMBIOSMinorVersion    Property     System.UInt16 SMBIOSMinorVersion {get;set;}
SMBIOSPresent         Property     System.Boolean SMBIOSPresent {get;set;}
SoftwareElementID     Property     System.String SoftwareElementID {get;set;}
SoftwareElementState  Property     System.UInt16 SoftwareElementState {get;set;}
Status                Property     System.String Status {get;set;}
TargetOperatingSystem Property     System.UInt16 TargetOperatingSystem {get;set;}
Version               Property     System.String Version {get;set;}
__CLASS               Property     System.String __CLASS {get;set;}
__DERIVATION          Property     System.String[] __DERIVATION {get;set;}
__DYNASTY             Property     System.String __DYNASTY {get;set;}
__GENUS               Property     System.Int32 __GENUS {get;set;}
__NAMESPACE           Property     System.String __NAMESPACE {get;set;}
__PATH                Property     System.String __PATH {get;set;}
__PROPERTY_COUNT      Property     System.Int32 __PROPERTY_COUNT {get;set;}
__RELPATH             Property     System.String __RELPATH {get;set;}
__SERVER              Property     System.String __SERVER {get;set;}
__SUPERCLASS          Property     System.String __SUPERCLASS {get;set;}
PSStatus              PropertySet  PSStatus {Status, Name, Caption, SMBIOSPresent}
ConvertFromDateTime   ScriptMethod System.Object ConvertFromDateTime();
ConvertToDateTime     ScriptMethod System.Object ConvertToDateTime();

That’s a pretty good list of 40 members, but there are actually many more that you might like to see as well.  For example, it can be useful to see the different member sets available on an object as well as any get_ and set_ methods that object has.  You can see that information by using the –Force parameter with Get-Member.  It can also be useful to see any hidden members that an object has, whether they come from the base member set, extended member set, or adapted member set.  To see all of these hidden members, you can use the –View parameter and specify you want to see members from All views.  When you put the –Force and –View parameters together, you end up with the following command:

Get-WmiObject Win32_BIOS | Get-Member -Force -View All

Running that command yields the following results:

   TypeName: System.Management.ManagementObject#root\cimv2\Win32_BIOS

Name                      MemberType            Definition
—-                      ———-            ———-
pstypenames               CodeProperty          System.Collections.ObjectModel.Collection`1[[System.String, mscorlib…
Disposed                  Event                 System.EventHandler Disposed(System.Object, System.EventArgs)
psadapted                 MemberSet             psadapted {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY, __RELPATH, __P…
psbase                    MemberSet             psbase {Scope, Path, Options, ClassPath, Properties, SystemPropertie…
psextended                MemberSet             psextended {ConvertToDateTime, ConvertFromDateTime, PSStatus}
psobject                  MemberSet             psobject {Members, Properties, Methods, ImmediateBaseObject, BaseObj…
PSStandardMembers         MemberSet             PSStandardMembers {DefaultDisplayPropertySet}
add_Disposed              Method                System.Void add_Disposed(System.EventHandler value)
Clone                     Method                System.Object Clone()
CompareTo                 Method                bool CompareTo(System.Management.ManagementBaseObject otherObject, S…
CopyTo                    Method                System.Management.ManagementPath CopyTo(System.Management.Management…
CreateObjRef              Method                System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
Delete                    Method                System.Void Delete(), System.Void Delete(System.Management.DeleteOpt…
Dispose                   Method                System.Void Dispose()
Equals                    Method                bool Equals(System.Object obj)
Get                       Method                System.Void Get(), System.Void Get(System.Management.ManagementOpera…
GetHashCode               Method                int GetHashCode()
GetLifetimeService        Method                System.Object GetLifetimeService()
GetMethodParameters       Method                System.Management.ManagementBaseObject GetMethodParameters(string me…
GetPropertyQualifierValue Method                System.Object GetPropertyQualifierValue(string propertyName, string …
GetPropertyValue          Method                System.Object GetPropertyValue(string propertyName)
GetQualifierValue         Method                System.Object GetQualifierValue(string qualifierName)
GetRelated                Method                System.Management.ManagementObjectCollection GetRelated(), System.Ma…
GetRelationships          Method                System.Management.ManagementObjectCollection GetRelationships(), Sys…
GetText                   Method                string GetText(System.Management.TextFormat format)
GetType                   Method                type GetType()
get_ClassPath             Method                System.Management.ManagementPath get_ClassPath()
get_Container             Method                System.ComponentModel.IContainer get_Container()
get_Item                  Method                System.Object get_Item(string propertyName)
get_Options               Method                System.Management.ObjectGetOptions get_Options()
get_Path                  Method                System.Management.ManagementPath get_Path()
get_Properties            Method                System.Management.PropertyDataCollection get_Properties()
get_Qualifiers            Method                System.Management.QualifierDataCollection get_Qualifiers()
get_Scope                 Method                System.Management.ManagementScope get_Scope()
get_Site                  Method                System.ComponentModel.ISite get_Site()
get_SystemProperties      Method                System.Management.PropertyDataCollection get_SystemProperties()
InitializeLifetimeService Method                System.Object InitializeLifetimeService()
InvokeMethod              Method                System.Object InvokeMethod(string methodName, System.Object[] args),…
Put                       Method                System.Management.ManagementPath Put(), System.Management.Management…
remove_Disposed           Method                System.Void remove_Disposed(System.EventHandler value)
SetPropertyQualifierValue Method                System.Void SetPropertyQualifierValue(string propertyName, string qu…
SetPropertyValue          Method                System.Void SetPropertyValue(string propertyName, System.Object prop…
SetQualifierValue         Method                System.Void SetQualifierValue(string qualifierName, System.Object qu…
set_Item                  Method                System.Void set_Item(string propertyName, System.Object value)
set_Options               Method                System.Void set_Options(System.Management.ObjectGetOptions value)
set_Path                  Method                System.Void set_Path(System.Management.ManagementPath value)
set_Scope                 Method                System.Void set_Scope(System.Management.ManagementScope value)
set_Site                  Method                System.Void set_Site(System.ComponentModel.ISite value)
ToString                  Method                string ToString()
Item                      ParameterizedProperty System.Object Item(string propertyName) {get;set;}
BiosCharacteristics       Property              System.UInt16[] BiosCharacteristics {get;set;}
BIOSVersion               Property              System.String[] BIOSVersion {get;set;}
BuildNumber               Property              System.String BuildNumber {get;set;}
Caption                   Property              System.String Caption {get;set;}
ClassPath                 Property              System.Management.ManagementPath ClassPath {get;}
CodeSet                   Property              System.String CodeSet {get;set;}
Container                 Property              System.ComponentModel.IContainer Container {get;}
CurrentLanguage           Property              System.String CurrentLanguage {get;set;}
Description               Property              System.String Description {get;set;}
IdentificationCode        Property              System.String IdentificationCode {get;set;}
InstallableLanguages      Property              System.UInt16 InstallableLanguages {get;set;}
InstallDate               Property              System.String InstallDate {get;set;}
LanguageEdition           Property              System.String LanguageEdition {get;set;}
ListOfLanguages           Property              System.String[] ListOfLanguages {get;set;}
Manufacturer              Property              System.String Manufacturer {get;set;}
Name                      Property              System.String Name {get;set;}
Options                   Property              System.Management.ObjectGetOptions Options {get;set;}
OtherTargetOS             Property              System.String OtherTargetOS {get;set;}
Path                      Property              System.Management.ManagementPath Path {get;set;}
PrimaryBIOS               Property              System.Boolean PrimaryBIOS {get;set;}
Properties                Property              System.Management.PropertyDataCollection Properties {get;}
Qualifiers                Property              System.Management.QualifierDataCollection Qualifiers {get;}
ReleaseDate               Property              System.String ReleaseDate {get;set;}
Scope                     Property              System.Management.ManagementScope Scope {get;set;}
SerialNumber              Property              System.String SerialNumber {get;set;}
Site                      Property              System.ComponentModel.ISite Site {get;set;}
SMBIOSBIOSVersion         Property              System.String SMBIOSBIOSVersion {get;set;}
SMBIOSMajorVersion        Property              System.UInt16 SMBIOSMajorVersion {get;set;}
SMBIOSMinorVersion        Property              System.UInt16 SMBIOSMinorVersion {get;set;}
SMBIOSPresent             Property              System.Boolean SMBIOSPresent {get;set;}
SoftwareElementID         Property              System.String SoftwareElementID {get;set;}
SoftwareElementState      Property              System.UInt16 SoftwareElementState {get;set;}
Status                    Property              System.String Status {get;set;}
SystemProperties          Property              System.Management.PropertyDataCollection SystemProperties {get;}
TargetOperatingSystem     Property              System.UInt16 TargetOperatingSystem {get;set;}
Version                   Property              System.String Version {get;set;}
__CLASS                   Property              System.String __CLASS {get;set;}
__DERIVATION              Property              System.String[] __DERIVATION {get;set;}
__DYNASTY                 Property              System.String __DYNASTY {get;set;}
__GENUS                   Property              System.Int32 __GENUS {get;set;}
__NAMESPACE               Property              System.String __NAMESPACE {get;set;}
__PATH                    Property              System.String __PATH {get;set;}
__PROPERTY_COUNT          Property              System.Int32 __PROPERTY_COUNT {get;set;}
__RELPATH                 Property              System.String __RELPATH {get;set;}
__SERVER                  Property              System.String __SERVER {get;set;}
__SUPERCLASS              Property              System.String __SUPERCLASS {get;set;}
PSStatus                  PropertySet           PSStatus {Status, Name, Caption, SMBIOSPresent}
ConvertFromDateTime       ScriptMethod          System.Object ConvertFromDateTime();
ConvertToDateTime         ScriptMethod          System.Object ConvertToDateTime();

That result set shows 99 members, which is a lot more than the 40 members you get to see by default!

As you can see, there is a lot more to these objects than meets the eye.  Using Get-Member with –Force and –View All is a great way to get all of the information you need about objects so that you really know what your objects contain and are capable of.

Kirk out.

Share this post :

PowerGUI Quick Tip: Create a PowerPack from start to finish in 10 minutes

This Sunday at midnight PST marks the closing of our second annual PowerPack Challenge contest.  The rules of this contest are very simple: create a new PowerPack or modify one of your existing PowerPacks and submit it to the contest folder in the PowerPack Library for a chance to win some cool prizes.  Now you might be thinking: "Sunday, but that’s  just three days away…I don’t have time to put together an entry between now and Sunday. Besides, I want my weekend to myself!"  Well, you’re in luck my friend because you don’t need three days…you only need 10 minutes (well, 10 minutes after you watch a screencast showing what you can do with PowerShell, the PowerGUI Admin Console, and 10 minutes of your time).  That’s not even going to take up your whole lunch hour on Friday, and if you plan to go out for lunch you could make your PowerPack during your afternoon break instead!

Here’s all you need to do:

1.  Bookmark the PowerPack section of the wiki.  I published a big update to our wiki earlier this week and it should be able to answer a lot of questions you might have.  Don’t read the whole thing right now though, that might take too long and what you really want to do right now is explained in the next step.

2.  Watch this screencast (also shown below on YouTube) that shows how I created a cool Windows Server Roles and Features PowerPack from scratch earlier today and published it to the PowerPack Library in only 10 minutes.  The PowerPack even has dynamic nodes generated from 4 script nodes, which used to be quite a lot of work but thanks to the AdminConsole module they are much, much easier now.  In fact, if you pay close attention to the screencast, you’ll see that all of the functionality in the PowerPack itself is done with only 7 lines of PowerShell script plus one basic node and two basic actions — that’s pretty amazing.  The entire screencast is longer than 10 minutes because I needed to explain a few things before and after the demonstration, but the creation and publishing of the PowerPack itself is done in only 10 minutes during the screencast.

Now that I’ve armed you with the wiki documentation and the screencast demo, I’ll be looking forward to seeing your PowerPacks in the PowerPack Library after your lunch or afternoon break! 😉

Good luck with your PowerPacks!

Kirk out.

Share this post:

Learn PowerShell v2 features using PowerShell code snippets

Learning and using PowerShell v2 features just got easier!  Earlier this week I uploaded a collection of PowerShell v2 code snippets to the PowerGUI website, and they are ready for you to download and use.  All you need to do is follow the installation instructions in the snippet document.

Once you have the snippets installed, watch the screencast that demonstrates how you can learn more about some PowerShell v2 features by using the v2 code snippets.  You can watch it in flash format with a table of contents, or you can watch the YouTube version below.

Want to see more snippets?  Let me know which areas of PowerShell you would like to see covered in snippets by leaving me a note in the comments.

Enjoy!

Kirk out.

Share this post:

PowerShell Quick Tip: When you store an array, make sure it is an array

It is not uncommon to want to store the results of a command in an array so that you can refer to the contents of that array later in your script.  This is often done by simply assigning the results of a command to a variable.  For example, if you were importing the contents of a csv file into an array you might do it like this:

$collection = Import-Csv C:\newusers.csv

Commands like this will work forever as long as you have a csv file in the appropriate location.  Occasionally though you may find that a script containing this command just stops working.  It might not make sense to you at the time because the script hasn’t changed, so what’s the problem?

The problem is that in the above command there is no guarantee that $collection will actually store an array of objects because there is no guarantee that Import-Csv will return more than one object.  In fact, there is no guarantee that Import-Csv will return any objects at all.  If the C:\newusers.csv file is generated by some other tool, it is possible that it might contain 0, 1 or more entries.  When it contains 0 or 1 entries, the $collection variable will either be $null or it will contain one object representing the single entry in the C:\newusers.csv file, respectively.  If further down in your script you’re always treating $collection as if it is an array and using indices to access elements in the array, your script will suddenly start failing with errors.

Fortunately there is a way to ensure that the results of any command are stored in an array.  All you need to do is wrap the command that returns the object(s) in array enclosures, like this:

$collection = @(Import-Csv C:\newusers.csv)

If you take this approach in your script and then later when you run your script C:\newusers.csv only contains one entry or perhaps doesn’t contain any entries at all, your $collection variable will still be an array so that you can check the size using the Count property ($collection.Count), access individual values using indices (e.g. $collection[0]), etc.  This is a much safer practice to take when writing your scripts so that you can make sure that you have an array when you store an array.

Of course if you are dealing with very large collections of objects that aren’t already loaded in memory an even better practice is to avoid storing the entire collection in memory altogether by using pipelines and cmdlets like ForEach-Object to process the items in the collection, but I wanted to make sure you were aware of how you should properly handle and store arrays in variables in your scripts so that you’re not facing a script long after it has been written and asking yourself why it suddenly stopped working.  There are plenty of other reasons why a script could stop working at some point but at least now you’re armed with the knowledge required to avoid one of those possibilities.

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:

PowerShell Quick Tip: Create aliases to facilitate invocation of PowerShell script (ps1) files

I was just reading Steve Murawski’s latest blog post which contains a script called ConvertTo-Function that allows you to generate a function from a script file.  The intent is to allow you to have scripts you don’t call as often, and therefore don’t load into your profile, but when you need them you can use this script to easily generate functions that wrap them so that you don’t need to think about the path beyond the initial call to the ConvertTo-Function script.  That’s one way to facilitate this, but I have something I use quite commonly in my own environment that works much better for me for this scenario: aliases.

Aliases can reference a path to a script file.

This capability is often overlooked because aliases are most commonly used and thought of as terse command names.  Using them to reference a path to a script file is quite useful because it allows you to keep all of your scripts, complete or in development, in a common location.  You can control which ones are loaded in your profile by only creating aliases for those scripts.  Alternatively, for scripts that you really don’t use very often, you could have a function in your profile to create the aliases to those scripts on an as needed basis (which sounds a little like the Add-Module capabilities in PowerShell v2).  In either case, using aliases to reference script files is very handy because you don’t need to worry about whether the scripts you want to invoke are in a folder in your path environment variable or not.  You simply need to create an alias to the full path and then you can use that alias to invoke your script.

For example, assuming you had a script with the path C:\MyScripts\Miscellaneous\Do-Something.ps1, you could invoke it using the absolute or relative path, or if C:\MyScripts\Miscellaneous happened to be in your path environment variable you could simply invoke it using the Do-Something command.  But if you don’t have your script path in your path environment variable and/or you don’t want to change that variable, aliases give you the same capability on a temporary basis for your current PowerShell session (and only in your current scope by default if you want it really temporary).  Using our example script path, all you would have to do is create a new alias with this command:

New-Alias Do-Something C:\MyScripts\Miscellaneous\Do-Something.ps1

That allows you to invoke your script any time you want to by simply using the Do-Something alias, as long as it is created and visible in the current scope.

Kirk out.

Share this post:

PowerShell Quick Tip: Use the command argument last when calling PowerShell.exe

Have you ever tried calling PowerShell.exe with the -NoExit argument and wondered why PowerShell is still exiting when it’s done your script?  For example, if you want to quickly launch a new clean PowerShell session that immediately runs a script, you might run this:

PowerShell.exe -Command “your script” -NoExit

When you do this, PowerShell still exits after it is done with your script.  Also, if you were paying attention it likely reports an error that references “NoExit”.  It seems that this happens because PowerShell.exe looks at all arguments after -Command and treats them as the command you want to execute in your new PowerShell session.

The solution to this problem is simple.  Always make -Command the last named argument in your argument list.  Looking at the above example, that means rearranging the command to look like this instead:

PowerShell.exe -NoExit -Command “your script

This will execute your script and leave PowerShell open for you to work with it afterwards.

Kirk out.

Share this post: