Monthly Archives: January 2013

PowerShell and Active Directory recording

The recording, slides and demo script from yesterday’s PowerShell and Active Directory session can be found here:

PowerShell workflows–now we are six


The sixth in the series of articles on PowerShell workflows that are appearing on the Scripting Guy blog has been published.

The articles in the series that have been published are:

Look for the next article in one weeks time.

Until then Enjoy!

PowerShell and Active Directory–reminder

Quick reminder for tomorrow’s session from the UK PowerShell group.  Details from:

Piping between functions

A question came up about piping between advanced functions. The input to the second function might be an array. To illustrate how this works imagine a function that gets disk information – or better still use this one.

function get-mydisk{             
param (             
Get-WmiObject -Class Win32_LogicalDisk -ComputerName $computername |            
foreach {            
New-Object -TypeName PSObject -Property @{            
 Disk = $_.DeviceID            
 Free = $_.FreeSpace            
 Size = $_.Size            

Use a computername as a parameter. Use WMI to get the disk information and output an object.

PS> get-mydisk | ft -AutoSize

Disk         Free         Size
----         ----         ----
C:   149778239488 249951154176
D:       69271552    104853504

This works as well


PS> get-mydisk | where Size -gt 0 | ft -AutoSize

Disk         Free         Size
----         ----         ----
C:   149778108416 249951154176
D:       69271552    104853504

You now have a function outputs objects that behave properly on the pipeline.

So now you want those objects piped into another function or you want an array of objects used as the input

function get-freeperc {             
param (             
foreach ($disk in $disklist){            
 if ($disk.Size -gt 0){            
   $disk | Select Disk,            
   @{N="Size(GB)"; E={[math]::Round( ($($_.Size)/1GB), 2 )}},            
   @{N="FreePerc"; E={[math]::Round( ($($_.Free) / $($_.Size))*100, 2 )}}            

  • Set the parameter to accept pipeline input
  • Set the parameter to accept an array of objects
  • Use a process block
  • Use a foreach block in the process block

This works

PS> get-mydisk | get-freeperc | ft -AutoSize

Disk Size(GB) FreePerc
---- -------- --------
C:     232.79    59.92
D:        0.1    66.07

or this

$disks = get-mydisk 
get-freeperc -disklist $disks 

or this

get-freeperc -disklist (get-mydisk)

Starting virtual machines for WSUS

My test environment usually has a dozen or so machines at any one time. Some of these are short lived and used for a particular piece of testing – others are kept for  years. I decided that I wanted to keep up to date on the patching of these virtual machines so installed WSUS on a Windows 2012 box.

One issue is that if a VM isn’t started for 10 days WSUS starts complaining that it hasn’t been contacted and if you run the WSUS clean up wizard the non-reporting servers may be removed. Checking the WSUS console for which machines haven’t sync’d recently is a chore.

In Windows 2012 both WSUS and Hyper-V come with a PowerShell module. This means I can do this:

$date = (Get-Date).AddDays(-10)            
Get-WsusComputer -ToLastSyncTime $date |            
sort  LastSyncTime |            
select -First 4 |            
foreach {             
 $computer = ($_.FullDomainName -split "\.")[0]            
 Start-VM -Name $computer -ComputerName Server02 -Passthru            

I’m using the WSUS server as my admin box but if you were accessing a remote WSUS machine change the code to

Get-WsusServer -Name w12sus -PortNumber 8530 | Get-WsusComputer –ToLastSyncTime $date |

I sorted the computers WSUS knows about by date – picked the last 4 to sync so I didn’t overwhelm the Hyper-V host and started them up. Only trick is to get the computer name out of the FullDomainName property.

Account SIDs–hopefully my last word

Ok the embarrassing moral of this story is that you shouldn't answer questions in a hurry at the end of the evening. 5 minutes after shutting down I realised that there is a far, far simpler way to get the info. Win32_AccountSID is a WMI linking class. It links Win32_SystemAccount and Win32_SID classes.

Get-WmiObject -Class Win32_SystemAccount | select Caption, Domain, Name, SID, LocalAccount

gets you all you need

Account SIDs revisited

I realised there is an easier way to get the data

function get-SID {            
param (            
 [string]$computername = $env:COMPUTERNAME            
Get-WmiObject -Class Win32_AccountSID -ComputerName $computername |            
foreach {            
 $exp = "[wmi]'" + $($_.Element) + "'"            
 Invoke-Expression -Command $exp |            
 select Domain, Name, SID, LocalAccount            

Use the wmi type accelerator with the path from the Element and you can just select the data you want.  As a bonus you can discover if the account is local or not

Passing function names

A question asked about passing a function name into another function which then called the function. It sounds worse than it is. if you need to pass the name of a command and then call it try using invoke-expression

function ffour {            
function fthree {            
function ftwo {            
Invoke-Expression $fname            
ftwo fthree            
ftwo ffour

Account SIDs

A question on the forum asked about finding the accounts and SIDs on the local machine.

function get-SID {            
param (            
 [string]$computername = $env:COMPUTERNAME            
Get-WmiObject -Class Win32_AccountSID -ComputerName $computername |            
foreach {            
 $da =  (($_.Element).Split(".")[1]).Split(",")            
 $sid = ($_.Setting -split "=")[1] -replace '"',''            
 $props = [ordered]@{            
 Domain = ($da[0] -split "=")[1] -replace '"',''            
 Account = ($da[1] -split "=")[1] -replace '"',''            
 SID = $sid            
 New-Object -TypeName PSObject -Property $props            

Pass a computer name into the function – default is local machine.

Use the AccountSID class which links Win32_SystemAccount and Win32_SID.  For each returned instance clean up the data and create an object with three properties – domain, account and SID.

You will see more than you thought – some very useful information buried in there

UK PowerShell group – 29 January 2013

When: Tuesday, Jan 29, 2013 7:30 PM (GMT)

Where: virtual


Active Directory is one of the commonest automation targets for administrators. This session will covert the basics of automating your AD admin - scripts and the Microsoft cmdlets. The new features in PowerShell for Windows 2012 AD will also be covered


Richard Siddaway has invited you to attend an online meeting using Live Meeting.
Join the meeting.
Audio Information
Computer Audio
To use computer audio, you need speakers and microphone, or a headset.
First Time Users:
To save time before the meeting, check your system to make sure it is ready to use Microsoft Office Live Meeting.
Unable to join the meeting? Follow these steps:

  1. Copy this address and paste it into your web browser:
  2. Copy and paste the required information:
    Meeting ID: RCRWH3
    Entry Code: 5p7$}S_!h

If you still cannot enter the meeting, contact support

Microsoft Office Live Meeting can be used to record meetings. By participating in this meeting, you agree that your communications may be monitored or recorded at any time during the meeting.