PowerShell for Windows Admins


April 16, 2014  11:30 AM

WMI against remote machines

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

WMI is a great tool for managing your Windows machines – I’d argue that PowerShell wouldn’t be as powerful as it is without WMI. If you question that remember that 60% of the additional cmdlets in Windows Server 2012 & 2012 R2 are CDXML based i.e. publish a WMI class as a PowerShell module.

PowerShell 2.0 introduced a suite of WMI cmdlets:

Get-WmiObject

Invoke-WmiMethod

Register-WmiEvent

Remove-WmiObject

Set-WmiInstance

PowerShell 3.0 introduced the CIM cmdlets:

Get-CimAssociatedInstance

Get-CimClass

Get-CimInstance

Get-CimSession

Invoke-CimMethod

New-CimInstance

New-CimSession

New-CimSessionOption

Register-CimIndicationEvent

Remove-CimInstance

Remove-CimSession

Set-CimInstance

 

So which should you use?

There are a number of differences.

The WMI cmdlets return live objects and the CIM cmdlets return inert objects. This isn’t too much of an issue if you use Invoke-CimMethod. I’d also recommend using Invoke-WMImethod over creating an object and calling the method on that.

The real difference is in the protocol used to access remote machines. The WMI cmdlets use DCOM and the CIM cmdlets default to WSMAN. At this point you may be thinking that you can just use the CIM cmdlets but the remote machine must be running WSMAN 3.0 which comes with PowerShell 3.0 or 4.0.. The CIM cmdlets can’t connect to WSMAN 2.0 which is the PowerShell 2.0 version.

At that point you have to use a CIM session that drops back to DCOM or run Get-WMIobject through a PowerShell remoting session.

Overall the CIM cmdlets win – especially when you consider Get-CimClass and Get-CimAssociatedInstance

 

 

April 15, 2014  10:06 AM

PowerShell versions

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

I’ve been using the CIM cmdlets for a number of posts recently and had a comment that a reader got a message that Get-CimInstance didn’t exist on their Windows 7 machine.

Windows 7 ships with PowerShell 2.0; Windows 8 with PowerShell 3.0 and Windows 8.1 with PowerShell 4.0.

You need PowerShell 3.0 or 4.0 to have the CIM cmdlets.

You can install PowerShell 3.0 or 4.0 on Windows 7. You need to go to the Microsoft download site, download and install the appropriate version of Windows Management Framework (WMF 3 contains PowerShell 3.0 and WMF 4 contains PowerShell 4.0).

You can tell which version of PowerShell you are running by looking in the $psversiontable automatic variable:

 

£> $psversiontable

Name Value

—- —–

PSVersion 4.0

WSManStackVersion 3.0

SerializationVersion 1.1.0.1

CLRVersion 4.0.30319.34014

BuildVersion 6.3.9600.16394

PSCompatibleVersions {1.0, 2.0, 3.0, 4.0}

PSRemotingProtocolVersion 2.2

 


April 14, 2014  2:43 PM

Status of Office software

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

You can also use the SoftwareLicensingProduct CIM class to test the status of your Office products.

Get-CimInstance -ClassName SoftwareLicensingProduct -Filter “Name LIKE ‘Office%’” |

where PartialProductKey |

select Name, ApplicationId, LicenseStatus

You need to be careful with Office as you might find a lot more options than you expected. On my machine I found this:

Get-CimInstance -ClassName SoftwareLicensingProduct -Filter “Name LIKE ‘Office%’” | select Name -Unique | sort name

Office 15, OfficeO365ProPlusR_Grace edition

Office 15, OfficeO365ProPlusR_Retail edition

Office 15, OfficeO365ProPlusR_Subscription1 edition

Office 15, OfficeO365ProPlusR_Subscription2 edition

Office 15, OfficeO365ProPlusR_Subscription3 edition

Office 15, OfficeO365ProPlusR_Subscription4 edition

Office 15, OfficeO365ProPlusR_Subscription5 edition

Office 15, OfficeO365ProPlusR_SubTrial1 edition

Office 15, OfficeO365ProPlusR_SubTrial2 edition

Office 15, OfficeO365ProPlusR_SubTrial3 edition

Office 15, OfficeO365ProPlusR_SubTrial4 edition

Office 15, OfficeO365ProPlusR_SubTrial5 edition

Office 15, OfficeO365SmallBusPremR_Grace edition

Office 15, OfficeO365SmallBusPremR_Retail edition

Office 15, OfficeO365SmallBusPremR_Subscription1 edition

Office 15, OfficeO365SmallBusPremR_Subscription2 edition

Office 15, OfficeO365SmallBusPremR_Subscription3 edition

Office 15, OfficeO365SmallBusPremR_Subscription4 edition

Office 15, OfficeO365SmallBusPremR_Subscription5 edition

Office 15, OfficeO365SmallBusPremR_SubTrial1 edition

Office 15, OfficeO365SmallBusPremR_SubTrial2 edition

Office 15, OfficeO365SmallBusPremR_SubTrial3 edition

Office 15, OfficeO365SmallBusPremR_SubTrial4 edition

Office 15, OfficeO365SmallBusPremR_SubTrial5 edition

Office 15, OfficeProjectProCO365R_Subscription edition

Office 15, OfficeProjectProCO365R_SubTest edition

Office 15, OfficeProjectProCO365R_SubTrial edition

Office 15, OfficeProjectProDemoR_BypassTrial180 edition

Office 15, OfficeProjectProMSDNR_Retail edition

Office 15, OfficeProjectProO365R_Subscription edition

Office 15, OfficeProjectProO365R_SubTest edition

Office 15, OfficeProjectProO365R_SubTrial edition

Office 15, OfficeProjectProR_Grace edition

Office 15, OfficeProjectProR_OEM_Perp edition

Office 15, OfficeProjectProR_Retail edition

Office 15, OfficeProjectProR_Trial edition

Office 15, OfficeProPlusDemoR_BypassTrial180 edition

Office 15, OfficeProPlusMSDNR_Retail edition

Office 15, OfficeProPlusR_Grace edition

Office 15, OfficeProPlusR_OEM_Perp edition

Office 15, OfficeProPlusR_Retail edition

Office 15, OfficeProPlusR_Trial edition

Office 15, OfficeVisioProCO365R_Subscription edition

Office 15, OfficeVisioProCO365R_SubTest edition

Office 15, OfficeVisioProCO365R_SubTrial edition

Office 15, OfficeVisioProDemoR_BypassTrial180 edition

Office 15, OfficeVisioProMSDNR_Retail edition

Office 15, OfficeVisioProO365R_Subscription edition

Office 15, OfficeVisioProO365R_SubTest edition

Office 15, OfficeVisioProO365R_SubTrial edition

Office 15, OfficeVisioProR_Grace edition

Office 15, OfficeVisioProR_OEM_Perp edition

Office 15, OfficeVisioProR_Retail edition

Office 15, OfficeVisioProR_Trial edition

 

which was a lot more than I expected.

It is possible to use WMI to set the product key – use the SoftwareLicensingService class

 


April 13, 2014  5:50 AM

Checking license activation

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

I’m building some virtual machines for my demo’s at the upcoming PowerShell summit. To make the demo’s, and setup, more interesting(?) I decided to use some Server Core instances.

The usual setup activities become a bit more interesting with Server Core – particular Windows activation.

Windows 2012 R2 will activate itself if the new machine has an Internet connection when it is created. With the GUI version of Windows you can check that Windows is activated using the System applet in Control Panel.

If you’re using Server Core you can use WMI to test activation:

Get-CimInstance -ClassName SoftwareLicensingProduct |

where PartialProductKey |

select Name, ApplicationId, LicenseStatus |

Format-List *

 

Use the SoftwareLicensingProduct WMI class and filter for PartialProductkey – that means a product key has been entered. You can then select the name of the product the ApplicationId and the LicenseStatus:

Name : Windows(R), ServerStandard edition

ApplicationId : 55c92734-d682-4d71-983e-d6ec3f16059f

LicenseStatus : 1

 

A License status of 1 indicates that its licensed – i.e. activated

More on using WMI to test and set activation in chapter 13 of PowerShell and WMI – www.manning.com/siddaway2

 

 


April 11, 2014  2:17 AM

PowerShell Deep Dive and Save the Children

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

I co-edited PowerShell Deep Dives – http://www.manning.com/hicks/ – alongside Jeff Hicks and other PowerShell MVPs.  The book is collection of chapters from  PowerShell experts from around the world.

The list of authors includes:

Jeffery Hicks, Richard Siddaway, Oisín Grehan, Aleksandar Nikolić, Chris Bellée, Bartek Bielawski, Robert C. Cain, Jim Christopher, Adam Driscoll, Josh Gavant, Jason Helmick, Don Jones, Ashley McGlone, Jonathan Medd, Ben Miller, James O’Neill, Arnaud Petitjean, Vadims Podans, Karl Prosser, Boe Prox, Matthew Reynolds, Mike Robbins, Donabel Santos, Will Steele, Trevor Sullivan, and Jeff Wouters.

Best of all the royalties from the book all go to Save the Children.  The more copies we sell the more they receive.  If you haven’t bought a copy please do so. Available from your favourite bookshop or direct from the publisher.


April 10, 2014  2:16 PM

Requires

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

A comment was left on my last post stating that the requires keyword could be used to test for modules.

Requires is a keyword that can be put at the top of scripts and modules. It will prevent the script or module running if the requirement isn’t met.  You can test for a number of items. This list is for  PowerShell 4.0.  earlier versions of PowerShell have fewer options.

PowerShell version:

#Requires –version 3

This means that the code will only run on PowerShell version 3 or later

PowerShell snapin

#Requires –PSSnapin Microsoft.Exchange.Management.PowerShell.E2010

Loads the Exchange snapin.  iIf its not available the script won’t continue.

Modules

#Requires -Modules PSWorkflow, @{ModuleName=”PSScheduledJob”;ModuleVersion=1.0.0.0}

Use the module name or a hash table with name, version and optionally the GUID for the module. If the required module can’t be loaded the script fails. This is different to my test-module function as I was only interested in discovery – I wasn’t actually using the test. If your script requires a module use the #Requires statement

Elevated privileges

#Requires –RunAsAdministrator

If PowerShell isn’t running with elevated privileges the script terminates.

ShellId

#Requires –ShellId Microsoft.PowerShell

This uses the default PowerShell Shell.  Note that the console and ISE both return Microsoft.PowerShell    when you test $shellid.  If you want to test for console vs ISE use

£> $host.name

ConsoleHost

£> $Host.Name

Windows PowerShell ISE Host


April 9, 2014  1:33 PM

Testing module existence

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

I had a comment left on an old post stating that Get-ADuser errored stating it wasn’t a cmdlet. This is because the module wasn’t loaded or on PowerShell 3 and above available to be auto-imported. That got me thinking about testing for a modules existence.

function test-module {

[CmdletBinding()]

param (

[Parameter(Mandatory=$true)]

[ValidateNotNullOrEmpty()]

[string]$name,

[Parameter(ParameterSetName='Installed')]

[switch]$installed,

[Parameter(ParameterSetName='Loaded')]

[switch]$loaded

)

switch ($psCmdlet.ParameterSetName) {

‘Installed’ {

Get-Module -Name “*$name*” -ListAvailable

break

}

‘Loaded’ {

Get-Module -Name “*$name*”

}

default {

Throw “Error!!! Should not be here”

}

}

}

 

Define a parameter for the module name and 2 switch parameters – loaded tests if the module is loaded into PowerShell and installed tests if the module can be found on the module path.

I’ve used parameter sets to make the switches mutually exclusive.

A switch statement based on the parameter set name calls the Get-Module in an appropriate manner. Notice that the module name you supply is wrapped in wildcards so you don’t have to type the full module name.

You can use the function like this:

test-module -name cim –installed

or

test-module -name cim -loaded

You can even do this:

if (-not (test-module -name cim -loaded)){throw “module not found”}

 


April 8, 2014  2:41 PM

Getting mailbox data and stats per database

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Way back in the day – http://richardspowershellblog.wordpress.com/2007/12/20/list-mailboxes-by-mailbox-database/ – I showed how to list mailboxes by the database in which they were stored. I had a comment left asking if its possible to list only a specific mailbox and to give the mailbox size as well.

To recap:

Get-Mailbox will return the list of mailboxes

This will quickly show the number of mailboxes per database

Get-Mailbox | group Database –NoElement

This shows the mailboxes in a particular database

Get-Mailbox -Database MDB1

To get the size you use Get-MailboxStatistics

So to put this together:

function get-mbxBYdb {

[CmdletBinding()]

param (

[Parameter(Mandatory=$true)]

[string]$database

)

Get-Mailbox -Database $database |

foreach {

$stat = $_ | Get-MailboxStatistics -WarningAction SilentlyContinue

New-Object -TypeName PSObject -Property @{

Name = $($_.DisplayName)

Address = $($_.PrimarySmtpAddress)

Database = $database

Items = $stat.ItemCount

‘Size(KB)’ = $stat.TotalItemSize.Value.ToKB()

}

}

}

The database name is a mandatory parameter. Get the mailboxes in the database and foreach get the mailbox statistics. You can then create an output object that combines the data from the mailbox object and the statistics object. Examine each type of object individually to determine the exact set of properties you need.

One trick with the size of items is that you can convert to specific size units as shown (MB, GB, TB and bytes are also available)


April 7, 2014  12:49 PM

Finding the class key

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Time to extend our module for investigating CIM. This time I want to show you how to find the key to the class.

You need to know the key property of a CIM class when you perform a number of actions – most particularly when you create an instance of the class. Its just a matter of iterating through the properties of the class to find any that have a qualifier called KEY.

function Get-ClassKey {

[CmdletBinding()]

param (

[Parameter(Mandatory=$true)]

[Alias("Class")]

[ValidateNotNullOrEmpty()]

[string]$classname,

[ValidateNotNullOrEmpty()]

[string]$namespace = ‘root/cimv2′

)

$class = Get-CimClass -ClassName $classname -Namespace $namespace

foreach ($property in $class.CimClassProperties) {

$property | select -ExpandProperty Qualifiers |

foreach {

if ($_.Name -eq ‘key’){

$property

}

}

}

}

 

The classname parameter is made mandatory and the namespace defaults to root/cimv2

Get the class and then loop through the each property – looking for a qualifier called key.


April 4, 2014  12:18 PM

Discovering namespaces part 2

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

I recently showed how to use Get-CimInstance to discover the namespaces present in a particular CIM namespace. I’m going to try to use CIM instaed of WMI but expect the old terminology to creep in occasionally.

The function I showed last time will only find the first level of namespaces in a namespace – what if those namespaces contain namespaces.

This is where you get to meet the concept of recursion. In this case all it means is that we’re going to call our function from within the function. Its easier to show with code.

function get-cimnamespace {

param (

[string]$namespace = ‘root/cimv2′,

[switch]$nobase

)

if (-not $nobase)

{

New-Object -TypeName psobject -Property @{

Name = $namespace

}

}

Get-CimInstance -ClassName __NameSpace -Namespace $namespace |

foreach {

$ns = New-Object -TypeName psobject -Property @{

Name = “$($psitem.CimSystemProperties.NameSpace)/$($psitem.Name)”

}

Write-Output $ns

get-cimnamespace -namespace $ns.Name -nobase

}

}

The function has 2 parameters – the startign namespace parameter and a switch parameter. The switch controls if the namespace used as a parameter is output.

Get-CimInstance is used to find each instance of the __Namespace class. Foreach instance the namespace name is output and then used to call get-cimnamespace with the new namespace as a paramter. Its already been output so the –nobase switch is used to prevent duplicate output. And that’s recursion.

On my test machine I get this

£> get-cimnamespace

Name

—-

root/cimv2

ROOT/cimv2/mdm

ROOT/cimv2/mdm/MS_40c

ROOT/cimv2/mdm/MS_809

ROOT/cimv2/mdm/MS_413

ROOT/cimv2/mdm/MS_409

ROOT/cimv2/mdm/MS_407

ROOT/cimv2/ms_40c

ROOT/cimv2/Security

ROOT/cimv2/Security/MicrosoftTpm

ROOT/cimv2/Security/MicrosoftVolumeEncryption

ROOT/cimv2/ms_809

ROOT/cimv2/power

ROOT/cimv2/power/MS_40c

ROOT/cimv2/power/ms_809

ROOT/cimv2/power/MS_413

ROOT/cimv2/power/ms_409

ROOT/cimv2/power/MS_407

ROOT/cimv2/ms_413

ROOT/cimv2/ms_409

ROOT/cimv2/TerminalServices

ROOT/cimv2/TerminalServices/ms_40c

ROOT/cimv2/TerminalServices/ms_809

ROOT/cimv2/TerminalServices/ms_413

ROOT/cimv2/TerminalServices/ms_407

ROOT/cimv2/ms_407

ROOT/cimv2/Applications

ROOT/cimv2/Applications/WindowsParentalControls

ROOT/cimv2/Applications/WindowsParentalControls/Secured

ROOT/cimv2/Applications/Games

ROOT/cimv2/Applications/Games/ms_40c

ROOT/cimv2/Applications/Games/ms_809

ROOT/cimv2/Applications/Games/ms_413

ROOT/cimv2/Applications/Games/ms_409

ROOT/cimv2/Applications/Games/ms_407

I’m loading the function as part of a CimInvetsigation module which now has 2 cmdlets:

Get-CimMethod

Get-CimNamespace


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: