Monthly Archives: May 2012

Scheduled tasks on clusters

This post shows how to use PowerShell in Windows Server 2012 to configure scheduled tasks that apply across the whole cluster not just a single node

http://blogs.msdn.com/b/clustering/archive/2012/05/31/10312527.aspx

Well worth a read

May 2012 Powershell group recording and slides

 

The recording, slides and demo scripts from last nights session  - Powershell in Windows Server 8 part 2  - is available from

https://skydrive.live.com/?cid=43cfa46a74cf3e96#cid=43CFA46A74CF3E96&id=43CFA46A74CF3E96%212966

The full set of historical recordings can be found here:

https://skydrive.live.com/#cid=43CFA46A74CF3E96&id=43CFA46A74CF3E96%212469

2011 09 PowerShell remoting and end point customisation
2011 11 Whats new in PowerCLI 5
2011 12 Intro to WMI
2011 12 WSMAN_WMI_and_CIM
2012 January PowerShell v3 CTP 2 overview
2012 February PowerShell and SQL Server
2012 March CIM cmdlets
2012 April Powershell in Windows Server 8
2012 May Powershell in Windows Server 8 part 2 

Older folders just have the slides

Some thoughts on hash tables

I need to test the existence of an element in a hash table.

First create a hash table

$myht = DATA {
ConvertFrom-StringData -StringData @'
1 = aaaaaaa
2 = bbbbbbb
3 = ccccccc
4 = ddddddd
5 = eeeeeee
'@
}

 

I tend to create them using ConvertFrom-StringData as it simplifies typing, I have a template for this and its easy to see what entries I’m making

lets see what happens

"1 = $($myht['1'])"
"6 = $($myht['6'])"

 

1 = aaaaaaa
6 =

 

The first test works as we would expect but interestingly we don’t get an error message when we try to access an element that doesn’t exist

So we can build on that

"1","6" | foreach {
if ($($myht[$_])){
  "$_ = $($myht[$_])"
}
else {
   "$_ not found"
}
}

 

a simple logic test shows if the element exists or not and we can branch from there

Life gets a bit more interesting when we are dealing with boolean and NULL values.  In this case I built hash table with three values as shown, true, false and null

$myht2 = @{"1"=$true; "2"=$false; "3"=$null}

 

if we run the same if statement

"1","2", "3", "4" | foreach {
if ($myht2[$_]){
  "$_ = $($myht2[$_])"
}
else {
   "$_ not found"
}
}

we get  this

1 = True
2 not found
3 not found
4 not found

which isn’t quite true

So lets try a switch statement


"1","2", "3", "4" | foreach {
  $x = $_
  switch ($myht2[$_]){
    $true   {"$x = $($myht2[$x])"}
    $false  {"$x is false"}
    $null   {"$x is null"}
    default {"$x not found"}
  }
}

1 = True
2 is false
3 is null
4 is null

 

Answers for 1,2 & 3 are OK but we can’t differentiate between an element that is null or a non-existent element.

The answer is that we need to think carefully about the data in our hash tables and how we test for existance

PowerShell v3 ISE

The ISE has a new look in PowerShell v3. The scripting pane remains but the output and interactive panes have been amalgamated to produce a single console like pane.

When I first saw it I didn’t like it but after jumping between PowerShell v2 and v3 recently the single console pane has grown on me and I actually prefer it as a way of working.

If you haven’t looked at PowerShell v3 yet now is the time to start. With the release candidate of Windows 8 expected in early June we will get the RC of PowerShell v3. Barring any last minute changes (more likely to be removals than additions – its just the way it works) thats what we will be working with once it ships.

My ISE add-ons like the ISE pack from the Windows 7 PowerShell powerpack still appear to work in the v3 version.

Can’t wait for the final release

May UG meeting reminder

Quick reminder that the UK PowerShell group session on PowerShell in Windows 2012 is on Tuesday 29 May. Details from

http://msmvps.com/blogs/richardsiddaway/archive/2012/05/08/uk-powershell-group-may-2012.aspx

Working with WMI methods

Many WMI classes have methods. Methods allow us to perform some action on the object. A recent question on the forum about using methods made me realise that there are still a lot of people following the old VBScript way of doing things.

We will experiment with the BITS service as it is safe for these purposes.

PS> Get-WmiObject -Class Win32_Service -Filter "Name = 'BITS'"


ExitCode  : 0
Name      : BITS
ProcessId : 928
StartMode : Auto
State     : Running
Status    : OK

Lets have a look at the service and its methods

$service = Get-WmiObject -Class Win32_Service -Filter "Name = 'BITS'"

$service | Get-Member -MemberType method

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

Name
----
Change
ChangeStartMode
Delete
GetSecurityDescriptor
InterrogateService
PauseService
ResumeService
SetSecurityDescriptor
StartService
StopService
UserControlService

So we see methods to stop and start the service

$service.StopService()

PS> Get-Service BITS

Status   Name               DisplayName
------   ----               -----------
Stopped  BITS               Background Intelligent Transfer Ser...

$service.StartService()

PS> Get-Service BITS

Status   Name               DisplayName
------   ----               -----------
Running  BITS               Background Intelligent Transfer Ser...

The person asking the question was trying to use the InvokeMethod method

$service.InvokeMethod('StopService',$Null)

and wondering why it was failing. If you look back to the list of methods above you won’t see InvokeMethod. That’s because it is on the base object. PowerShell, in many instances, doesn’t return the pure .NET object. There are methods and properties added or removed to create the object we normally see.

We can get back to the base object

$service.psbase | gm

And in that list you will see a method called InvokeMethod

PS> $service.psbase.InvokeMethod

OverloadDefinitions
-------------------
System.Object InvokeMethod(string methodName, System.Object[] args)
void InvokeMethod(System.Management.ManagementOperationObserver watcher, string methodName, System.Object[] args)
System.Management.ManagementBaseObject InvokeMethod(string methodName, System.Management.ManagementBaseObject
inParameters, System.Management.InvokeMethodOptions options)
void InvokeMethod(System.Management.ManagementOperationObserver watcher, string methodName,
System.Management.ManagementBaseObject inParameters, System.Management.InvokeMethodOptions options)

Shows us how to use it.

Going for the simplest option

PS> $service.psbase.InvokeMethod("StopService", $null)
0
PS> Get-Service BITS

Status   Name               DisplayName
------   ----               -----------
Stopped  BITS               Background Intelligent Transfer Ser...


PS> $service.psbase.InvokeMethod("StartService", $null)
0
PS> Get-Service BITS

Status   Name               DisplayName
------   ----               -----------
Running  BITS               Background Intelligent Transfer Ser...

PS> Get-WmiObject -Class Win32_Service -Filter "Name = 'BITS'" | Invoke-WmiMethod -Name StopService


PS> Get-Service BITS

Status   Name               DisplayName
------   ----               -----------
Stopped  BITS               Background Intelligent Transfer Ser...


PS> Get-WmiObject -Class Win32_Service -Filter "Name = 'BITS'" | Invoke-WmiMethod -Name StartService


PS> Get-Service BITS

Status   Name               DisplayName
------   ----               -----------
Running  BITS               Background Intelligent Transfer Ser...

These options will work as well

$service | Invoke-WmiMethod -Name StopService
$service | Invoke-WmiMethod -Name StartService

Invoke-WmiMethod -InputObject $service -Name StopService
Invoke-WmiMethod -InputObject $service -Name StartService

My preference is to use the get-wmiobject | invoke-wmimethod pairing as when I am developing I can easily test any filters before I start affecting the service.

Of all of the options using the  InvokeMethod method is the one to avoid as it is more cumbersome and involves more typing

In PowerShell v3 we can use the CIM cmdlets but that is a post for another day

More information on using WMI with PowerShell in PowerShell and WMI – www.manning.com/powershellandwmi

Unblocking Files with PowerShell v3

There are a number of new features in PowerShell v3 that while not huge like CIM or workflow are os significant help to the hard pressed administrator.  One of these is the Unblock-File cmdlet.

If you haven’t updated your help the online version is available at http://technet.microsoft.com/en-us/library/hh849924.aspx

To test it I downloaded the PowerShell v2 release notes from

http://www.microsoft.com/en-us/download/details.aspx?id=11539

 

The gives me a file

Windows Mangement Framework Release Notes en-US.rtf

 

When you download a file – internet explorer safety mechanisms kick in and the file is blocked. This prevents a number of things happening including running scripts

You can test if a file is blocked by right clicking the file and looking at its properties – it will have an Unblock button at the bottom right of the dialog.

You can also use PowerShell to do this.

First we need to identify the files that are blocked.  These are files with an Alternative Data Stream of “Zone.Identifier”

 

PS> Get-Item -Path "c:\test\Windows Mangement Framework Release Notes en-US.rtf" -Stream "Zone.Identifier"


   FileName: C:\test\Windows Mangement Framework Release Notes en-US.rtf

Stream                   Length
------                   ------
Zone.Identifier              26

 

If you try to test multiple files

Get-Item -Path c:\test\*.* -Stream "Zone.Identifier"

be prepared for lots of error messages when the system doesn’t find an alternative data stream.  Better still control the error messages

Get-Item -Path c:\test\*.* -Stream "Zone.Identifier" -ErrorAction SilentlyContinue

  FileName: C:\test\indice_analitico.pdf

Stream                   Length
------                   ------
Zone.Identifier              26


   FileName: C:\test\Windows Mangement Framework Release Notes en-US.rtf

Stream                   Length
------                   ------
Zone.Identifier              26

Now I don’t recognise that pdf file so I’ll leave that for later

Either of these will filter on the extension

Get-Item -Path c:\test\*.rtf -Stream "Zone.Identifier" -ErrorAction SilentlyContinue
Get-Item -Path c:\test\*.* -Filter *.rtf -Stream "Zone.Identifier" -ErrorAction SilentlyContinue

Once you have the file

Get-Item -Path c:\test\*.* -Filter *.rtf -Stream "Zone.Identifier" -ErrorAction SilentlyContinue | Unblock-File

won’t work because only the –LiteralPath parameter of Unblock-File takes pipeline input and that’s by property name

 

These two options will work

Get-Item -Path c:\test\*.* -Filter *.rtf -Stream "Zone.Identifier" -ErrorAction SilentlyContinue |
foreach {Unblock-File -Path $_.FileName }

 

Get-ChildItem -Path c:\test\*.* -Filter *.rtf | Unblock-File

 

I prefer the first because it allows me to test and then modify to perform the unblock.

WMI providers

I found a class new to me - Msft_Providers and this got me interested in WMI providers.

PS> Get-CimInstance -Class Msft_Providers | select -ExpandProperty provider
Msft_ProviderSubSystem
SCM Event Provider
WmiPerfClass

 

That seems a bit low. Digging a bit more I got back to the old favourite __provider.

Get-CimInstance -Class __provider | Measure-Object

produces an answer of 43 – not quite the answer to life, the universe and everything but close.

Is there any overlap between the two groups of providers?

$providers = Get-CimInstance -Class Msft_Providers | select -ExpandProperty provider           
Get-CimInstance -Class __provider | where Name -in $providers | select Name

 

provides the answer

Msft_ProviderSubSystem  

SCM Event Provider

 

In case you were wondering – “Starting with Windows Vista, the WMIPerfClass Provider and the WMIPerfInst Provider dynamically provide performance counter data for the WMI Performance Counter Classes.”

see http://msdn.microsoft.com/en-us/library/windows/desktop/aa392740(v=vs.85).aspx

 

One interesting property is the Hosting Model

Get-CimInstance -Class __provider | select HostingModel -Unique

Decoupled:NonCOM
NetworkServiceHost
WmiCore
LocalSystemHost
LocalServiceHost

NetworkServiceHost:[ReliabilityMetricsProvider]

 

But what do these mean

Full explanations for these and the other hosting models can be found at

http://msdn.microsoft.com/en-us/library/aa392509(VS.85).aspx

WmiCore - Activate provider in host to the WMI service. This hosting model is only supported for operating system components.

WmiCoreOrSelfHost - Activate provider in host to the WMI service or as local server. This hosting model is only supported for operating system components.

SelfHost - Activate provider as a local server implementation.

Decoupled:Com - Activate provider as a decoupled COM provider. See http://msdn.microsoft.com/en-us/library/aa390882(v=vs.85).aspx
 
Decoupled:NonCom - Activate provider as a non-COM event provider.
 
LocalSystemHost - Activate provider in the provider host process that is running under the LocalSystem account.

LocalSystemHostOrSelfHost - The provider is self-hosted or loaded into the Wmiprvse.exe process running under the LocalSystem account.

NetworkServiceHost - Activate provider in the provider host process that is running under the NetworkService account.

LocalServiceHost - Activate provider in the provider host process that is running under the LocalService account.

NetworkServiceHostOrSelfHost - The provider is self-hosted or loaded into the WmiPrvse.exe process running under the NetworkService account. NetworkServiceHostOrSelfHost is the default configuration when the HostingModel property in __Win32Provider is NULL. Because NetworkServiceHostOrSelfHost is the default, providers from earlier operating systems can continue to work in Windows Vista, Windows Server 2008, and later operating systems.

Get-CIMInstance is a new cmdlet in PowerShell v3. It is part of the new API for working with WMI. I will be blogging about these in greater detail over the next weeks and months as Powershell v3 is released.

More information on providers and the CIM cmdlets can be found in PowerShell and WMIwww.manning.com/powershellandwmi

Where-object in PowerShell v3

Where-Object – aliased to where, but never, ever, ever, ever to ? – had a very simple syntax in PowerShell v2

Where-Object [-FilterScript] <scriptblock> [-InputObject <psobject>] [<CommonParameters>]

It was normally used as

Get-Process | where {$_.CPU -gt 25}

The –FilterScript parameter (positional as 1 so don’t have to use it) supplies a script block that performs the filtering. In this case it looks at the current object on the pipeline (indicated by $_) and compares the CPU property to 25. If the property has a greater value it is passed.

Any of the comparison operators could be used in the filter block.

With PowerShell v3 it gets easier

Get-Process | where CPU -gt 25

We can just give the property name, the comparison operator and the value. 

This only works for a single property. You can’t do this

PS> Get-Process | where CPU -gt 25 -and Handles -gt 2000
Where-Object : Cannot bind parameter because parameter 'gt' is specified more than once. To provide multiple values to
parameters that can accept multiple values, use the array syntax. For example, "-parameter value1,value2,value3".
At line:1 char:45
+ Get-Process | where CPU -gt 25 -and Handles -gt 2000
+                                             ~~~
    + CategoryInfo          : InvalidArgument: (:) [Where-Object], ParameterBindingException
    + FullyQualifiedErrorId : ParameterAlreadyBound,Microsoft.PowerShell.Commands.WhereObjectCommand

You have to go back to

Get-Process | where {$_.CPU -gt 25 -and $_.Handles -gt 2000}

but hang on a minute the error message said that gt is a parameter!

If you look at the help file for where-object you will see lots of lines like this

Where-Object [-FilterScript] <ScriptBlock> [-InputObject <PSObject>] [<CommonParameters>]
  
Where-Object [-Property] <String> [[-Value] <Object>] [-EQ [<SwitchParameter>]] [-InputObject <PSObject>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -Contains [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -GE [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -In [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CContains [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CEQ [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CGE [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CGT [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CIn [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CLE [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CLike [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CLT [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CMatch [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CNE [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CNotContains [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CNotIn [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CNotLike [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CNotMatch [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -Is [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -IsNot [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -LE [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -Like [<SwitchParameter>] <CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -LT [<SwitchParameter>] <CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -Match [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -NE [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -NotContains [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -NotIn [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -NotLike [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -NotMatch [<SwitchParameter>] [<CommonParameters>]

The first option is the PowerShell v2 version. 

Notice that the comparison operators are switch parameters and each is in a different parameter set – thats why you can’t have multiples

This is a very useful addition to where-object that simplifies syntax (we often only perform a single comparison in the filter) and reduces typing.

It still doesn’t change the fact that you should never, ever, ever, ever alias where-object to ?

UK PowerShell group–next two meetings

29 May 2012

PowerShell and Windows server 2012 – new functionality pt 2

http://msmvps.com/blogs/richardsiddaway/archive/2012/05/08/uk-powershell-group-may-2012.aspx

 

4 July

Jonathan Medd

XenDesktop and PowerShell

This will be at the slightly later time of 8.30 BST.  Details to follow