PowerShell for Windows Admins


July 12, 2014  4:28 AM

Time to stock up your book collection?

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Active Directory, Books

Manning are offering 40% off everything – print & ebooks – www.manning.com. They have a very extensive set of PowerShell books – now would be the time to add to your collection

July 11, 2014  12:39 PM

CIM or WMI – - accessing remote machines

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
CIM, WMI

I much prefer the CIM cmdlets for accessing remote machines. The WMI cmdlets use DCOM which is firewall unfriendly and can often be unavailable of a server – cue the dreaded RPC server is unavailable error messages.

By contrast the CIM cmdlets use WSMAN.

For one off access to a remote machine use the computername parameter

Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName RSSURFACEPRO2

 

If you want to access a machine multiple times in the session create a CIM session – analagous to a remoting session

 

$cs = New-CimSession -ComputerName RSSURFACEPRO2
Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $cs

 

By default a CIM session uses WSMAN

£> $cs
Id           : 1
Name         : CimSession1
InstanceId   : 30c2b530-4ff7-448e-b68d-1f1282890e6a
ComputerName : RSSURFACEPRO2
Protocol     : WSMAN

 

though you can configure them to use DCOM if need be

$opt = New-CimSessionOption -Protocol DCOM
$csd = New-CimSession -ComputerName RSSURFACEPRO2 -SessionOption $opt
Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $csd

 

When would you need to use DCOM – if you are accessing a machine with PowerShell 2 installed. The CIM cmdlets want to use WSMAN 3 and will error if you access a machine with WSMAN 2 installed however if you include a –Filter they will work

So

Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName computer1

will fail if computer1 is running WSMAN 2 (PowerShell 2)

However, if you change the command to include a filter

Get-CimInstance -ClassName Win32_OperatingSystem -Filter “Manufacturer LIKE ‘Microsoft%’” -ComputerName computer1

 

Even if, as in this case, the filter doesn’t actually do anything


July 9, 2014  1:29 PM

PowerShell Summit Europe 2014 – - update 4

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Registration will open next Tuesday (15th July) – that’s less than 1 week


July 7, 2014  12:45 PM

Finding a CIM class

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
CIM, WMI

I was investigating something on my disks and started to look at the partitions:

£> Get-CimInstance -ClassName Win32_Partition
Get-CimInstance : Invalid class
At line:1 char:1
+ Get-CimInstance -ClassName Win32_Partition
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : MetadataError: (root\cimv2:Win32_Partition:String) [Get-CimInstance], CimException
+ FullyQualifiedErrorId : HRESULT 0×80041010,Microsoft.Management.Infrastructure.CimCmdlets.GetCimInstanceCommand

OK so my memory isn’t what it was and I got the class name wrong. How to find the correct class?

£> Get-CimClass *Partition*
NameSpace: ROOT/cimv2

CimClassName
————
CIM_DiskPartition
Win32_DiskPartition
Win32_SystemPartitions
CIM_LogicalDiskBasedOnPartition
Win32_LogicalDiskToPartition
CIM_RealizesDiskPartition
Win32_DiskDriveToDiskPartition
Win32_PerfFormattedData_HvStats_…
Win32_PerfRawData_HvStats_HyperV…
Win32_PerfFormattedData_HvStats_…
Win32_PerfRawData_HvStats_HyperV…
Win32_PerfFormattedData_VidPerfP…
Win32_PerfRawData_VidPerfProvide…

 

I’ve truncated the display horizontally as not interested in methods & properties at this point
So the class I want is Win32_DiskPartition.

Get-CimClass is one of the biggest benefits from PowerShell 3.0


July 6, 2014  3:22 PM

CIM or WMI – - using methods

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
CIM, WMI

The CIM and WMI cmdlets both provide a way to use the methods on CIM classes namely Invoke-CimMethod and Invoke-WmiMethod. The cmdlets are very similar in operation.

$vol = Get-WmiObject -Class Win32_Volume -Filter “DriveLetter = ‘D:’”

Invoke-WmiMethod -InputObject $vol -Name Chkdsk -ArgumentList $false, $true, $true, $false, $false, $false

 

The argumenst list isn’t very informative – unless you know the class, read the documentation or investigate with Get-CimClass

 

Using the CIM cmdlets is a bit more informative as to what is going on.

$vol = Get-CimInstance -ClassName Win32_Volume -Filter “DriveLetter = ‘D:’”

Invoke-CimMethod -InputObject $vol -MethodName Chkdsk -Arguments @{FixErrors=$false; ForceDismount=$false; OkToRunAtB
ootUp = $false; RecoverBadSectors = $false; SkipFolderCycle = $true; VigorousIndexCheck = $true}

 

You present the arguments as a hash table – this means you can create the hash table and pass it to the method

$margs = @{
FixErrors=$false
ForceDismount=$false
OkToRunAtBootUp = $false
RecoverBadSectors = $false
SkipFolderCycle = $true
VigorousIndexCheck = $true
}
Invoke-CimMethod -InputObject $vol -MethodName Chkdsk -Arguments $margs

 

This also means that you can create a default set of values and manipulate them in your scripts very easily

 

Using Invoke-CimMethod involves more typing but I think that’s worth it for the clarity. Of course if you are going to be using the methods of class a lot then I’d recommend that you create a CDXML module from the class – but that’s a whole different set of articles.


July 6, 2014  8:50 AM

Workflows 7: checkpointing workflows

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Workflow

Consider this workflow

workflow chkpt1 {

Get-Process

foreach ($x in 1..20){
$x
}

}

 

It will dump out the process information then output the numbers 1 to 20.  Not a particularly enlightening workflow but it forms  a nice basis for demonstrating checkpoints.

A checkpoint saves the state and data in the workflow. If the workflow is suspended or interrupted the work flow can be restarted from the most recent checkpoint rather than a complete restart from the beginning.

 

Change the workflow to give a long running activity

workflow chkpt1 {

Get-Process
foreach ($x in 1..1000){
$x
}

}

Let the process data be displayed and then stop execution once the numbers start displaying – this is easiest if you use ISE. If you want to restart the workflow you have to start it right from the beginning.

Add a checkpoint to the workflow. This can be achieved in a number of ways.

Use the Checkpoint-Workflow activity to the workflow.

workflow chkpt1 {

Get-Process
Checkpoint-Workflow

foreach ($x in 1..1000){
$x
}

}

 

or use the –PSPersist parameter

workflow chkpt1 {

Get-Process -PSPersist
foreach ($x in 1..1000){
$x
}

}

 

I prefer to use Checkpoint-Workflow as it is more obvious to me when I review the workflow.

 

if you want to checkpoint your workflows – you have to start them as a job

 

chkpt1 –AsJob

 

Then shut down ISE

Open another PowerShell session with elevated privileges. Use Get-Job to see the suspended job.

View the data in the job

Receive-Job -Id 5 –Keep

 

Restart the job

Resume-Job -Id 5

 

Once the job finishes view the data and you’ll see the process data and the list of numbers.

Use Checkpoint-Workflow as many time as necessary to protect your data in long running workflows. A checkpoint is a good idea any time that it would be expensive to restart the whole process.


July 3, 2014  2:58 PM

and finally

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

If you’re old enough and seen UK TV you’ll recognise the title but this post is about using try – catch blocks.

Using try-catch this is a fairly normal construction

try {
Get-CimInstance -ClassName Win32_LogicalDisk  -ErrorAction Stop
}
catch {
Throw “something went wrong”
}

The number of commands within the try block should be minimised so that you stand a chance of knowing what you are going to catch.

if you introduce an error – for instance using the wrong classname

£> try {
Get-CimInstance -ClassName Win32_LogicalDrive  -ErrorAction Stop
}
catch {
Throw “something went wrong”
}
something went wrong
At line:5 char:2
+  Throw “something went wrong”
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : OperationStopped: (something went wrong:String) [], RuntimeException
+ FullyQualifiedErrorId : something went wrong

 

You can control what happens and even recover.

I don’t see the third element of a try-catch block being used much – that’s the finally block. The finally block will run irrespectively of whether the try block works or not. It’s your clean up block

Consider

£> try {
$cs = New-CimSession -ComputerName $env:COMPUTERNAME
Get-CimInstance -ClassName Win32_LogicalDrive  -CimSession $cs -ErrorAction Stop
}
catch {
Throw “something went wrong”
}
something went wrong
At line:6 char:2
+  Throw “something went wrong”
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : OperationStopped: (something went wrong:String) [], RuntimeException
+ FullyQualifiedErrorId : something went wrong
£> Get-CimSession
Id           : 1
Name         : CimSession1
InstanceId   : 68a4f534-d222-4e52-b6f9-ba65b1d57b3b
ComputerName : RSSURFACEPRO2
Protocol     : WSMAN

 

This try block fails but it leaves a CIM session hanging about. Not good practice. I know it will get cleaned up when you close the powershell session but that could be hours away. Better to clean up now.

£> try {
$cs = New-CimSession -ComputerName $env:COMPUTERNAME
Get-CimInstance -ClassName Win32_LogicalDrive  -CimSession $cs -ErrorAction Stop
}
catch {
Throw “something went wrong”
}
finally {
Remove-CimSession -CimSession $cs
}

Get-CimSession
something went wrong
At line:6 char:2
+  Throw “something went wrong”
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : OperationStopped: (something went wrong:String) [], RuntimeException
+ FullyQualifiedErrorId : something went wrong
no sign of a CIM session even if you try specifically.

 

£> Get-CimSession

£>

if you correct the code

try {
$cs = New-CimSession -ComputerName $env:COMPUTERNAME
Get-CimInstance -ClassName Win32_LogicalDisk  -CimSession $cs -ErrorAction Stop
}
catch {
Throw “something went wrong”
}
finally {
Remove-CimSession -CimSession $cs
}

Get-CimSession

 

You’ll find the the CIM session is still removed. A finally block will always run

When you are using try blocks think about your environment and use a finally block to clean up.


July 2, 2014  1:20 PM

CIM or WMI?

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
WMI

Working with WMI became a whole easier when PowerShell came on the scene. If you ever spent hours typing all of the Echo commands that were required with VBScript to produce output you’ll be aware of what I mean.  There are still a few awkward areas in the WMI cmdlets. One of the most awkward is date/time handling.

Consider looking for the last boot up time of your favourite computer:

£> Get-WmiObject -Class Win32_OperatingSystem | select -ExpandProperty LastBootUpTime
20140702083855.487133+060

 

That breaks down as year (2014), month (07), day (02), hour (08), minute (38), second (55) and fraction of a second (.487133). The +060 denotes the minutes offset from GMT (UTC if you prefer) – I’m in the UK on daylight saving time.  So, once you know how to read it the answer is understandable but not easy to work with.

The PowerShell team introduced a method on Get-WmiObject that will convert the date to a more understandable format:

 

£> $os = Get-WmiObject -Class Win32_OperatingSystem
£> $os.ConvertToDateTime($os.LastBootUpTime)

02 July 2014 08:38:55

 

You can also use the method in select-object or the format cmdlets by using a calculated field:

£> Get-WmiObject -Class Win32_OperatingSystem | Format-List PSComputerName, Caption, @{N=’BootTime’; E={$_.ConvertToDate
Time($_.LastBootUpTime)}}
PSComputerName : RSSURFACEPRO2
Caption        : Microsoft Windows 8.1 Pro
BootTime       : 02/07/2014 08:38:55

 

There is an easier way – use the CIM cmdlets:

£> Get-CimInstance -ClassName Win32_OperatingSystem | select -ExpandProperty LastBootUpTime

02 July 2014 08:38:55

 

The automatic date conversion is more than sufficient incentive for me to use Get-CimInstance in preference to Get-WmiObject.


July 1, 2014  2:32 PM

PowerShell Summit Europe 2014 – - update 3

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Registration for the Summit opens in 14 days – 15th July

If you need some help selling the idea of attending to your boss cheeck out this post http://richardspowershellblog.wordpress.com/2014/06/21/powershell-summit-europe-2014-reasons-to-attend-1-7/


June 30, 2014  12:55 PM

Workflows 6: suspending jobs

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Workflow

One of the great things about work flows is that you can stop and start them. A workflow can be stopped, on a temporary basis, by using the Suspend-Workflow activity.

workflow suspend1 {
Get-Service

Suspend-Workflow

Get-Process

}
suspend1

 

This will run the Get-Service activity – and produce output to the console. The workflow will suspend and automatically create a job. You will see output like this:

HasMoreData     : True
StatusMessage   :
Location        : localhost
StartParameters : {}
Command         : suspend1
JobStateInfo    : Suspended
Finished        : System.Threading.ManualResetEvent
InstanceId      : bbe0903d-1720-46da-a6dd-e0a927aa9e11
Id              : 8
Name            : Job8
ChildJobs       : {Job9}
PSBeginTime     : 30/06/2014 19:40:29
PSEndTime       : 30/06/2014 19:40:29
PSJobTypeName   : PSWorkflowJob
Output          : {}
Error           : {}
Progress        : {}
Verbose         : {}
Debug           : {}
Warning         : {}
State           : Suspended

 

Notice the state.

You can  manage the job with the standard job cmdlets

£> Get-Job

Id Name PSJobTypeName State     HasMoreData Location  Command
– —- ————- —–     ———– ——–  ——-
8  Job8 PSWorkflowJob Suspended True        localhost suspend1

 

The job is restarted using Resume-Job. Once the job has finished you can use Receive-Job to get the rest of the data.


Forgot Password

No problem! Submit your e-mail address below. We'll send you an e-mail containing your password.

Your password has been sent to: