Here are a few tips to use Powershell without using Google.
I know my way around Powershell quite OK. But I Googled a lot and when in a hurry I copied and pasted a lot. So I never took the time to be really in depth. Now is the time! And there is a way to write Powershell without Google! You need to know some very basics and how to study cmndlets, methods and properties.
Let's go!
Suppose you want to check if there are any PST's on a harddrive and let's pretend you know nothing, just like John 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 (a function) with 'dir' in it.
PS C:\Users\Jacqueline> get-command '*dir*' CommandType Name ----------- ---- 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. And you will want to update them. 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:
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.
PS C:\> save-help -DestinationPath C:\powershell\help2 -force -UICulture en-US
and then (as an Administrator):
PS C:\> Update-Help -SourcePath C:\powershell\help2\ -force -UICulture en-US
Now you can use the help files.
Using the help
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:
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:
SYNTAX Get-ChildItem [[-Path]] [[-Filter] ] [-Exclude ] [-Force] [-Include ] [-Name] [-Recurse] [-UseTransaction [ ]] [ ] Get-ChildItem [[-Filter] ] [-Exclude ] [-Force] [-Include ] [-Name] [-Recurse] -LiteralPath [-UseTransacti on [ ]] [ ] Get-ChildItem [-Attributes ] [-Directory] [-File] [-Force] [-Hidden] [-ReadOnly] [-System] [-UseTransaction] [ ]
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. Let's see how we can define an array in Powershell.
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:
$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:
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:
get-childitem -path $search -Recurse -Include "*.pst"
I don't want to look at all those red error messages, so let's suppress them:
get-childitem -path $search -Recurse -Include "*.pst" -ErrorAction silentlycontinue
And now for real:
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:
$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.
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:
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?
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.
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:
$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':
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.