header image

Archive for PowerShellV2

PowerShell 2.0 Engine removed from Server 2016

Posted by: | July 5, 2016 Comments Off on PowerShell 2.0 Engine removed from Server 2016 |

I hadn’t realised that the PowerShell 2.0 engine had been removed from Windows Server 2016 TP5


PS C:\Windows\system32> Get-WindowsFeature  PowerShell-V2 | ft -a

Display Name                          Name          Install State
————                          —-          ————-
    [ ] Windows PowerShell 2.0 Engine PowerShell-V2       Removed


Probably about time it disappeared. Can’t think of a reason you’d need it on Server 2016

under: PowerShell v5, PowerShellV2, Windows Server 2016

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 {
param (

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)

under: Exchange, PowerShellV2

My series on PowerShell Jobs for the Scripting Guy blog has finished.  The set of articles is:

Jobs week 1 : Introduction to PowerShell jobs

Jobs week 2 : WMi and CIM jobs

Jobs week 3 : Remote Jobs

Jobs week 4 : Scheduled Jobs

Jobs week 5 : Workflow Jobs

Jobs week 6 : Job processes

Jobs week 7 : Jobs in the enterprise



under: PowerShell original, PowerShell V3, PowerShell v4, PowerShellV2

CDXML–scripting creation

Posted by: | December 5, 2013 | No Comment |

So far you’ve seen how to create CDXML files by hand – though you probably used cut and paste rather than typing everything from scratch.

Its time to bring a bit of automation to creating CDXML files. The XML is fairly simple and you’re only changing a couple of values so you can do this:

function new-cdxml {
param (
[string]$namespace = ‘ROOT\cimv2’,
[string]$path = "C:\Scripts\Modules\Hardware"

$code = @"
<?xml version=’1.0′ encoding=’utf-8′?>
<PowerShellMetadata xmlns=’http://schemas.microsoft.com/cmdlets-over-objects/2009/11′>
  <Class ClassName=’$namespace\$class’>

      <GetCmdletParameters DefaultCmdletParameterSet=’DefaultSet’>

$file = Join-Path -Path $path -ChildPath "$class.cdxml"
Write-Verbose -Message  $file
Set-Content -Path $file -Value $code


I saved this as NewCDXML.ps1.  This will eventually  become the basis of a CDXML file creation module. I set defaults on the namespace and the path – feel free to change them if required.

The function is run as:

new-cdxml -class Win32_DiskDrive -noun PhysicalDisk

which produces this CDXML file

<?xml version=’1.0′ encoding=’utf-8′?>
<PowerShellMetadata xmlns=’http://schemas.microsoft.com/cmdlets-over-objects/2009/11′>
  <Class ClassName=’ROOT\cimv2\Win32_DiskDrive’>

      <GetCmdletParameters DefaultCmdletParameterSet=’DefaultSet’>


The Hardware.psd1 file needs to be altered:

# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
NestedModules = @(‘Win32_BIOS.cdxml’,



# Functions to export from this module
FunctionsToExport = @(‘Get-Bios’,


The module now looks like this:

£> Get-Command -Module Hardware

CommandType      Name
———–                —-
Function                Get-Bios
Function                Get-ComputerSystem
Function                Get-PhysicalDisk


This makes creating additional components for your module much easier.

under: CDXML, PowerShell and CIM, PowerShell and WMI, PowerShell V3, PowerShellV2

It’s the little things

Posted by: | August 29, 2013 | No Comment |

I’ve been spending some quality time with PowerShell 2.0 recently. When it was all we had it was great but there’s a bunch of things I miss from PowerShell 3.0 including:

CIM cmdlets

CIM sessions


Module auto loading

Improved tab completion

PowerShell 3.0 ISE especially the combined input/output panes

Of them all it’s the last three that I really miss the most. You become accustomed to the new features and how they make your life easier. To quote “You don’t know what you’ve got ‘til it’s gone”.

So very true but you appreciate them more when you get back to using them.

under: PowerShell V3, PowerShellV2

When I was writing the DNS chapter of PowerShell in Practice I couldn’t get the CreateInstanceFromPropertyData  method on the MicrosoftDNS_PTRType  class to work. Revisiting DNS for AD management in a Month of lunches this time round I have access to the CIM cmdlets so can put the parameter names in.  This gives usage like this.  I’ve shown Invoke-WmiMethod and Invoke-CimMethod so you can see the parameter names:

Invoke-WmiMethod -Namespace root\MicrosoftDNS -Class MicrosoftDNS_PTRType `
-Name CreateInstanceFromPropertyData `
-ArgumentList "175.168.192.in-addr.arpa", ‘server02’, ‘’,

Invoke-CimMethod -Namespace root\MicrosoftDNS -ClassName MicrosoftDNS_PTRType `
-MethodName CreateInstanceFromPropertyData `
-Arguments @{Containername = "175.168.192.in-addr.arpa";
DnsServerName = ‘server02’; OwnerName = ‘’;
PTRDomainName ="ADMLServer02.admldns.test"}


If you have access to Windows 2012 then you are better off using the cmdlet

Add-DnsServerResourceRecordPtr –Name ‘54’ `
–ZoneName “175.168.192.in-addr.arpa” `
–PtrDomainName  ‘ADMLServer01.admldns.test’  `
–ComputerName server02


Which ever method you use – you can easily create PTR records

under: DNS, PowerShell and WMI, PowerShell V3, PowerShellV2

A forum question regarding retrieving WMI based data from multiple servers and displaying it as HTML was interesting.  I would approach it like this

$servers = Get-Content -Path C:\scripts\servers.txt            
$data = @()            
foreach ($server in $servers){            
 $compdata = New-Object -TypeName PSObject -Property @{            
  Computer = $server            
  Contactable = $false            
  LastBootTime = ""            
  AllowTSConnections = $false            
 if (Test-Connection -ComputerName $server -Quiet -Count 1){            
   $compdata.Contactable = $true            
   $os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $server            
   $compdata.LastBootTime = $os.ConvertToDateTime($os.LastBootUpTime)            
   $ts = Get-WmiObject -Namespace root\cimv2\terminalservices -Class Win32_TerminalServiceSetting -ComputerName $server -Authentication PacketPrivacy            
   if ($ts.AllowTSConnections -eq 1){            
    $compdata.AllowTSConnections = $true            
 $data += $compdata            
$data | ConvertTo-Html | Out-File -FilePath c:\scripts\report.html            
Invoke-Item -Path c:\scripts\report.html

Put the list of servers in a text file & read it in via get-content.

use foreach to iterate over the list of servers.

For each server create an object and then test if you can ping the server. Note that the default setting for Contactable is $false so don’t need to deal with that case.

Get the WMI data and set the properties on the object.

Add the object to an array

After you’ve hit all the servers use ConvertTo-Html and write to a file with out-file.

use Invoke-Item to view the report

under: PowerShell and WMI, PowerShell V3, PowerShellV2

A question on the forum about a function had me thinking. The user had defined two parameters for the function and then used Read-Host to get the values.


Much better way is to use an advanced function and make the parameters mandatory

function Getuserdetails {            
param (            
Get-ADUser -properties telephonenumber,office -Filter {(GivenName -eq $Givenname) -and (Surname -eq $Surname)}             

If you call the function and don’t give values for the parameters you will be prompted for them

The other point is the –Filter property on get-aduser.  Don’t put quotes round the variable

under: PowerShell and Active Directory, PowerShell Basics, PowerShell V3, PowerShellV2

WMI property names

Posted by: | June 24, 2012 | No Comment |

A question brought it home to me that WMI property names don’t always mean what you might think they mean – this is also true of other objects but I tripped over this one with WMI so we’ll stick with that.

PS> Get-CimInstance -ClassName Win32_Desktop -Filter "Name LIKE ‘%Richard’" |
>> Format-List ScreenSaver*

ScreenSaverActive     : True
ScreenSaverExecutable : C:\Windows\system32\PhotoScreensaver.scr
ScreenSaverSecure     : True
ScreenSaverTimeout    : 600


The ScreenSaverActive property doesn’t mean that the screen saver is currently active – it means that one has been set!   This is doubly confusing because the documentation states

Data type: boolean
Access type: Read-only

Screen saver is active.

Which would lead you to think that is was actually running!

The ScreenSaverSecure means that a password has been set to unlock the system once the screen saver kicks in & ScreenSaverTimeout is the idle time in seconds before the screen saver kicks in. The executable is the screen saver that will be used.

If you want to get the information with the WMI cmdlets use

PS> Get-WmiObject Win32_Desktop -Filter "Name LIKE ‘%Richard’" |
>> Format-List ScreenSaver*

ScreenSaverActive     : True
ScreenSaverExecutable : C:\Windows\system32\PhotoScreensaver.scr
ScreenSaverSecure     : True
ScreenSaverTimeout    : 600

under: PowerShell and WMI, PowerShell V3, PowerShellV2

I recently (1 June) showed how to discover the user profiles on your system. Now its time to delete them.

function remove-profile {            
 param (            
 $user = Get-CimInstance -Class Win32_UserAccount -Filter "Name = '$username'"             
 $profile = Get-CimInstance -Class Win32_UserProfile -Filter "SID = '$($user.SID)'"            
 $folder = Split-Path -Path $profile.LocalPath -Leaf            
 if ($folder -eq $username){            
  Remove-CimInstance -InputObject $profile            
 else {            
  Write-Warning -Message "Could not resolve profile and user name"             

I’m going to start with the CIM cmdlets as these are the way of the future in PowerShell v3.

Start by taking a user name as a parameter. Get the Win32_UserAccount class object representing that account. use the SID to find the profile via Win32_UserProfile.  Take the profile’s localpath and split it. The last part of the path should match the username – if it does then delete the profile otherwise throw a warning. Deleting the profile does delete the folder under c:\users

If you have to use the WMI cmdlets then its very similar

function remove-profile {            
 param (            
 $user = Get-WmiObject -Class Win32_UserAccount -Filter "Name = '$username'"             
 $profile = Get-WmiObject -Class Win32_UserProfile -Filter "SID = '$($user.SID)'"            
 $folder = Split-Path -Path $profile.LocalPath -Leaf            
 if ($folder -eq $username){            
  Remove-WmiObject -InputObject $profile            
 else {            
  Write-Warning -Message "Could not resolve profile and user name"             

Just the name of the cmdlets change.

You can’t use WMI to delete local accounts as explained on page 363 of PowerShell and WMI 

If you have profiles generated by AD accounts you’ll need to find the SID from the AD account and use that as the filter for deletion

under: PowerShell and WMI, PowerShell V3, PowerShellV2

Older Posts »