Powershell Without Google

| Comments

At work I find myself using Powershell a lot. Here are a few tips to use Powershell without Googling all the time.

Suppose you want to check if there are any PST’s on a harddrive and let’s pretend you know nothing, just like Jon Snow.

Find out what cmdlets are available with Get-Command

Obviously we need to recurse directories to see if there are any files with a .pst extension. So let’s see if there’s a cmdlet.aspx) with ‘dir’ in it.

1
2
3
4
5
6
7
PS C:\Users\Jacqueline> get-command '*dir*'

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           chdir -> Set-Location
Alias           dir -> Get-ChildItem
Alias           rmdir -> Remove-Item

Get-ChildItem looks like the cmdlet we need. Let’s see how it works with the help files.

Get the help files

The problem with command line interfaces: you can’t ‘guess’ which command to use and what the parameters are. So you will need to read the help files. Unfortunately, the help files are in c:\windows\system32, so you need to run the command as an Administrator.

You can only update-help once a day unless you use the -Force parameter.

So open a console as an Admin and run:

1
PS C:\> update-help -UICulture en-US -force

Needless to say an Internet connection is required. What if you don’t have one?

Saving help to an alternate location

In that case you can save the help files on an alternate location or on a netwerk share and then update-help.

1
PS C:\> save-help -DestinationPath C:\powershell\help2 -force -UICulture en-US

and then (as an Administrator):

1
PS C:\> Update-Help -SourcePath C:\powershell\help2\ -force -UICulture en-US

Now you can use the help files.

Using the help

1
PS C:\> Help Get-ChildItem

Will display all there is to know about Get-Childitem. Like parameters and what kind of parameters it accepts (string, arrays and so on). If you scroll down the help you get to see the remarks:

1
2
3
4
5
REMARKS
    To see the examples, type: "get-help Get-ChildItem -examples".
    For more information, type: "get-help Get-ChildItem -detailed".
    For technical information, type: "get-help Get-ChildItem -full".
    For online help, type: "get-help Get-ChildItem -online"

The -examples are very convenient if you want to have a quick solution.

So now we can play a bit with Get-ChildItem. Let’s discover its syntax:

1
2
3
4
5
6
7
8
9
10

SYNTAX
    Get-ChildItem [[-Path] <String[]>] [[-Filter] <String>] [-Exclude <String[]>] [-Force] [-Include <String[]>] [-Name] [-Recurse] [-UseTransaction
    [<SwitchParameter>]] [<CommonParameters>]

    Get-ChildItem [[-Filter] <String>] [-Exclude <String[]>] [-Force] [-Include <String[]>] [-Name] [-Recurse] -LiteralPath <String[]> [-UseTransacti
    on [<SwitchParameter>]] [<CommonParameters>]

    Get-ChildItem [-Attributes <FileAttributes]>] [-Directory] [-File] [-Force] [-Hidden] [-ReadOnly] [-System] [-UseTransaction] [<CommonParameters>
    ]

Here we see it accepts a -Path parameter which is an array because there are brackets: String[]. So we can input multiple search locations by creating an array of locations.

Now type:

1
get-help array

And you will see you get very valuable information about how to create an array. I could create an array like this:

1
$search = @($env:HOMEPATH,"c:\temp")

Notice the quotes around c:\temp because we’re dealing with strings. The $env:HOMEPATH is already a variable which returns a string.

We can test the array like follows:

1
2
3
4
PS C:\Users\Jacqueline> $search = @($env:HOMEPATH\Dropbox,"c:\temp")
PS C:\Users\Jacqueline> $search
\Users\Jacqueline\Dropbox
c:\temp

Now we can do a search ilke this:

1
get-childitem -path $search -Recurse -Include "*.pst" 

I don’t want to look at all those red error messages, so let’s suppress them:

1
get-childitem -path $search -Recurse -Include "*.pst" -ErrorAction silentlycontinue

And now for real:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PS C:\Temp> get-childitem -path $search -Recurse -Include "*.pst" -ErrorAction SilentlyContinue


    Directory: C:\Users\Jacqueline\Dropbox\work


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----         5-4-2013     18:33      211305472 jacqueline.pst


    Directory: C:\temp


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        26-7-2015     13:12        5242880 archive.pst
-a----        26-7-2015     13:12        5242880 old.pst

Let’s put the result in a variable, like so:

1
$pst = Get-ChildItem -Path "c:\" -Include "*.pst" -Recurse -ErrorAction SilentlyContinue

Investigating $pst with Get-Member

Like Get-Command and Get-Help, Get-Member is a really import cmdlet you should know about. With Get-Member we can investigate which properties and methods are available. How can I actually write a script or type a command-line command without having to memorize every object model found on MSDN?

Once you connect to an object you can pipe that object to Get-Member; in turn, Get-Member will enumerate the properties and methods of that object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

PS C:\Temp> $pst | Get-Member

   TypeName: System.IO.FileInfo

Name                      MemberType     Definition
----                      ----------     ----------
Mode                      CodeProperty   System.String Mode{get=Mode;}
AppendText                Method         System.IO.StreamWriter AppendText()
CopyTo                    Method         System.IO.FileInfo CopyTo(string destFileName), System.IO.FileInfo... Create                    Method         System.IO.FileStream Create()
CreateObjRef              Method         System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
CreateText                Method         System.IO.StreamWriter CreateText()
Decrypt                   Method         void Decrypt()
Delete                    Method         void Delete()
Encrypt                   Method         void Encrypt()
Equals                    Method         bool Equals(System.Object obj)

--MORE

Scrolling down the list you will notice a Method GetType. Let’s run that:

1
2
3
4
5
PS C:\Temp> $pst.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

So $pst is an Array (we already knew that..) but what is in the array?

1
2
3
4
5
6

PS C:\Temp> $pst | ForEach-Object { write-host $_.GetType()}
System.IO.FileInfo
System.IO.FileInfo
System.IO.FileInfo
System.IO.FileInfo

So, we’ve got an array full of FileInfo objects. Each objects has a set of methods and properties, which we can query by using Get-Member.

Fun stuff to do with arrays

Powershell and any other scripting language is all about gathering input, do stuff with this input and generate the output. You can send the objects through the pipeline and sort them and query them.

So let’s do that with the $pst array.

  • Sort the array alphabetically: $pst | Select-Object name,lastwritetime,fullname | Sort-Object lastwritetime
  • Only show the pst with my name in it: PS C:\Temp> $pst | Where-Object {$_.Name -match "jacq*"}

Copying and renaming the PST’s to another location

Let’s copy the PST’s to another location and rename then so some admin can import the PST into a mailbox.

Just copying is not that hard:

1
$pst | Copy-Item -Destination C:\Temp\pst-share

But if I want to rename the file as well I have to be a bit more ‘developerish’:

1
2
3
4
foreach ($f in $pst) {
    $name = $env:USERNAME + "-" + $f.Name
    Copy-Item $f.FullName -Destination "C:\temp\pst-share\$name"
  }

Let’s debate on this script tomorrow.

Comments