Posts RSS Comments RSS 244 Posts and 356 Comments till now

Archive for June, 2007

Using Aliases in Scripts or in your Examples.

Richard has a post on his blog about this The Over Use of Aliases?

I dont like duplicating other peoples post, but I think this one is worth it.

If you are an experienced Powershell person and you provide help or scripts to people. PLEASE do not use aliases. It makes it very hard for people. I am guilty myself. I mean gc % ? gm are SO tempting, but it really doesn’t help the person learn (it may even hinder.) IMO, using aliases can confuse newcomers… remember to them when you type gc… they think it is gc.exe not get-content. Peoples first impression is key… lets not make it a confusing one :)

Basically, I think aliases are best use for interactive use, but should be avoided in scripts or sample code.

p.s. COMMENT… COMMENT… COMMENT… Comments in code help a ton for people learning.

UPDATE:
Jeffrey brought up a good point that I over looked. Numerous Powershell IDE’s like PrimalScript and Powershell Analzyer automatically expand built in aliases. I find this very useful. I will be writing another post about IDE’s and why I think they are VERY important.

More on Select-Object

I had a few question on what I meant by “select-object does Change the object type and therefore you lose methods and properties you may expect to be there.” So Here is an example to help clarify.

First let me show the object type Change

26# ($dir = Get-item C:\temp).Gettype()

IsPublic IsSerial Name                                     BaseType
——– ——– —-                                     ——–
True     True     DirectoryInfo                            System.IO.FileSystemInfo

27# ($dir = Get-item C:\temp | select-Object Fullname,Name,Parent).Gettype()

IsPublic IsSerial Name                                     BaseType
——– ——– —-                                     ——–
True     False    PSCustomObject                           System.Object
 

Even if you specifiy PSBASE you have new object type.

28# ($dir = Get-item C:\temp).psbase.Gettype()

IsPublic IsSerial Name                                     BaseType
——– ——– —-                                     ——–
True     True     DirectoryInfo                            System.IO.FileSystemInfo

29# ($dir = Get-item C:\temp | select-Object Fullname,Name,Parent).psbase.Gettype()

IsPublic IsSerial Name                                     BaseType
——– ——– —-                                     ——–
True     False    PSCustomObject                           System.Object
>/pre>

Now look at what you lose using this method.

First you will notice you have 21 items returned from Get-Member
(I only included Properties for simplicity, but methods work the same way.)
<pre lang="posh">
18# get-item c:\temp | Get-Member -MemberType Properties | ft Name

Name
—-
PSChildName
PSDrive
PSIsContainer
PSParentPath
PSPath
PSProvider
Attributes
CreationTime
CreationTimeUtc
Exists
Extension
FullName
LastAccessTime
LastAccessTimeUtc
LastWriteTime
LastWriteTimeUtc
Name
Parent
Root
Mode
ReparsePoint
 

After piping to Select-Object you now only have 3

24# Get-Item C:\temp | Select-Object Name,Fullname,Parent | Get-Member -MemberType Properties | ft name

Name
—-
FullName
Name
Parent
 

Now.. methods before “Conversion”

32# Get-item C:\temp | Get-Member -MemberType Methods | ft name

Name
—-
Create
CreateObjRef
CreateSubdirectory
Delete
Equals
GetAccessControl
GetDirectories
GetFiles
GetFileSystemInfos
GetHashCode
GetLifetimeService
GetObjectData
GetType
get_Attributes
get_CreationTime
get_CreationTimeUtc
get_Exists
get_Extension
get_FullName
get_LastAccessTime
get_LastAccessTimeUtc
get_LastWriteTime
get_LastWriteTimeUtc
get_Name
get_Parent
get_Root
InitializeLifetimeService
MoveTo
Refresh
SetAccessControl
set_Attributes
set_CreationTime
set_CreationTimeUtc
set_LastAccessTime
set_LastAccessTimeUtc
set_LastWriteTime
set_LastWriteTimeUtc
ToString
 

After

33# Get-item C:\temp | select-object FullName,Name,Parent | Get-Member -MemberType Methods | ft name

Name
—-
Equals
GetHashCode
GetType
ToString
 

As you can see… Effectively they are all gone on the new object. When I first experienced this.. I thought maybe the methods were just hidden… but try to access them

42# $dir = Get-Item C:\temp
43# $dir.GetDirectories()

Mode           LastWriteTime       Length Name
—-           ————-       —— —-
d—-     5/22/2007  1:58 PM              Console
d—-     5/10/2007  4:36 PM              test32

44# $dir = Get-Item C:\temp | Select-Object FullName,Name,Parent
45# $dir.GetDirectories()
Method invocation failed because [System.Management.Automation.PSCustomObject] doesn‘t contain a method named ‘GetDirectories‘.
At line:1 char:20
+ $dir.GetDirectories( <<<< )

I want to be clear… This is not a bug. Its not even a bad idea. I find it useful, but I think it confuses a lot of people. Like most people I didnt read the help before I used it or I would have seen this excerpt from get-help Select-Object:

[code]
If you use Select-Object to select specified properties, it copies the values of those properties from the input objects and
creates new objects that have the specified properties and copied values.
[/code]

Creating Custom Objects

halr9000 Asked “can you explain this construct for me?”

[code]$myobj = ""| select-Object Server,Result[/code]

IMO this is the simplest way to create custom objects.

Effectively what happens is you set your $myobj to a empty string and pipe to select-object.
While this may seem odd, its actually quite useful because what select-object returns is
a PSCustomObject with the properties that you specify. This allows you to create you object
with defined properties that you can fill out later in one line.

I guess the “proper” way to create a custom object is to do this.

[code]
$myobj = new-object System.Object
$myobj | add-member -membertype noteproperty -name Server -value $sname
$myobj | add-member -membertype noteproperty -name Result -value $sResult
[/code]

While this isnt that much more work… I think its harder to read so I go with my shortcut like

[code]
$myobj = "" | select-Object Server,Result
$myobj.Server = $sname
$myobj.Result = $sResult
[/code]

I will give you one warning about select-object (not related, but while I’m on this subject.) select-object does Change the object type and therefore you lose methods and properties you may expect to be there. I have seen numerous post on the news groups that have this exact problem.

If you pipe Get-ChildItem to Get-member you get tons of methods and
properties for both System.IO.FileInfo and System.IO.DirectoryInfo
[code]4# get-childitem | gm[/code]

Now pipe it to select-object and do a Get-Member
[code]
5# (get-childitem | select-object Fullname,length) | gm

TypeName: System.Management.Automation.PSCustomObject

Name MemberType Definition
---- ---------- ----------
Equals Method System.Boolean Equals(Object obj)
GetHashCode Method System.Int32 GetHashCode()
GetType Method System.Type GetType()
ToString Method System.String ToString()
FullName NoteProperty System.String FullName=C:\Windows\System32\0409
length NoteProperty length=null
[/code]

Just be careful to remember this. I actually avoid using select-object to filter objects simply because of this. Instead… I just use the properties.

How to Manage Multiple Citrix Farms

Chris left a comment on Powershelling Citrix (The Good, Bad, and The Code)

Here is a function that returns a farm object for Server that is passed.

function Get-CitrixFarm {
   Param([string]$server)
   $type = [system.Type]::GetTypeFromProgID("MetaframeCOM.MetaFrameFarm",$server)
   $farm = [system.Activator]::CreateInstance($type)
   $farm.Initialize(1)
   return $farm
}
 

Here is an example to find a Server that a User is on.

function Find-CitrixUser {
    Param([string]$user,[string]$server,[string]$domain,[switch]$verbose)
    $type = [system.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeUser",$server)
    $mfuser = [system.Activator]::CreateInstance($type)
    $mfuser.Initialize(1,$domain,1,$user)
    Write-Host
    Write-Host "User: $($mfuser.UserName) found on the Following:"
    foreach ($s in $mfuser.Sessions)
    {
        if($verbose)
        {
            Write-Host
            Write-Host "$($s.ServerName)"
            Write-Host "-=-=-=-=-=-"
            Write-Host "AppName          : $($s.AppName)" -foregroundcolor yellow
            Write-Host "SessionName      : $($s.SessionName)" -foregroundcolor yellow
            Write-Host "SessionID        : $($s.SessionID)" -foregroundcolor yellow
            Write-Host "ClientAddress    : $($s.ClientAddress)" -foregroundcolor yellow
            Write-Host "ClientEncryption : $($s.ClientEncryption)" -foregroundcolor yellow
            Write-Host
            Write-Host "Processes"
            Write-Host "========="
            foreach ($proc in $s.Processes)
            {
                Write-Host $proc.ProcessName -foregroundcolor Green
            }
            Write-host
        }
        else
        {
            write-Host "   -> $($s.ServerName)"
        }
    }
}