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:

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

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:

http://blogs.technet.com/b/heyscriptingguy/archive/2012/12/26/powershell-workflows-the-basics.aspx
http://blogs.technet.com/b/heyscriptingguy/archive/2013/01/02/powershell-workflows-restrictions.aspx
http://blogs.technet.com/b/heyscriptingguy/archive/2013/01/09/powershell-workflows-nesting.aspx
http://blogs.technet.com/b/heyscriptingguy/archive/2013/01/16/powershell-workflows-job-engine.aspx
http://blogs.technet.com/b/heyscriptingguy/archive/2013/01/23/powershell-workflows-restarting-the-computer.aspx
http://blogs.technet.com/b/heyscriptingguy/archive/2013/01/30/powershell-workflows-using-parameters.aspx

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:

http://msmvps.com/blogs/richardsiddaway/archive/2013/01/16/uk-powershell-group-29-january-2013.aspx

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{             
[CmdletBinding()]             
param (             
   [string]$computername="$env:COMPUTERNAME"             
)             
BEGIN{}#begin             
PROCESS{            
Get-WmiObject -Class Win32_LogicalDisk -ComputerName $computername |            
foreach {            
New-Object -TypeName PSObject -Property @{            
 Disk = $_.DeviceID            
 Free = $_.FreeSpace            
 Size = $_.Size            
}            
}            
}#process             
END{}#end            
}


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
E:                           
F:                           



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 {             
[CmdletBinding()]             
param (             
[parameter(ValueFromPipeline=$true)]            
  [Object[]]$disklist             
)             
BEGIN{}#begin             
PROCESS{            
            
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 )}}            
 }            
}            
            
}#process             
END{}#end            
}


  • 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 {            
Get-Random            
}            
            
            
function fthree {            
Get-Date            
}            
            
            
function ftwo {            
param(            
 [string]$fname            
)            
            
Invoke-Expression $fname            
}            
            
            
"date"            
ftwo fthree            
            
"random"            
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

Notes



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.
Troubleshooting
Unable to join the meeting? Follow these steps:

  1. Copy this address and paste it into your web browser:
    https://www.livemeeting.com/cc/usergroups/join
  2. Copy and paste the required information:
    Meeting ID: RCRWH3
    Entry Code: 5p7$}S_!h
    Location: https://www.livemeeting.com/cc/usergroups

If you still cannot enter the meeting, contact support

Notice
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.