PowerShell for Windows Admins


February 18, 2013  1:37 PM

Filtering

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

I’ve been grading the scripts in the warm up events for the Scripting Games and noticed a lot of people doing this:

Get-WmiObject -Class Win32_LogicalDisk | where {$_.DriveType -eq 3}

Ok now it works but there are a couple of things wrong with this approach.

Firstly, you are ignoring the built in capabilities of the get-wmiobject cmdlet

PS> Get-Command Get-WmiObject -Syntax

Get-WmiObject [-Class] <string> [[-Property] <string[]>] [-Filter <string>] [-Amended] [-DirectRead] [-AsJob]
[-Impersonation <ImpersonationLevel>] [-Authentication <AuthenticationLevel>] [-Locale <string>]
[-EnableAllPrivileges] [-Authority <string>] [-Credential <pscredential>] [-ThrottleLimit <int>] [-ComputerName
<string[]>] [-Namespace <string>] [<CommonParameters>]

Get-WmiObject [[-Class] <string>] [-Recurse] [-Amended] [-List] [-AsJob] [-Impersonation <ImpersonationLevel>]
[-Authentication <AuthenticationLevel>] [-Locale <string>] [-EnableAllPrivileges] [-Authority <string>] [-Credential
<pscredential>] [-ThrottleLimit <int>] [-ComputerName <string[]>] [-Namespace <string>] [<CommonParameters>]

Get-WmiObject -Query <string> [-Amended] [-DirectRead] [-AsJob] [-Impersonation <ImpersonationLevel>] [-Authentication
<AuthenticationLevel>] [-Locale <string>] [-EnableAllPrivileges] [-Authority <string>] [-Credential <pscredential>]
[-ThrottleLimit <int>] [-ComputerName <string[]>] [-Namespace <string>] [<CommonParameters>]

Get-WmiObject [-Amended] [-AsJob] [-Impersonation <ImpersonationLevel>] [-Authentication <AuthenticationLevel>]
[-Locale <string>] [-EnableAllPrivileges] [-Authority <string>] [-Credential <pscredential>] [-ThrottleLimit <int>]
[-ComputerName <string[]>] [-Namespace <string>] [<CommonParameters>]

Get-WmiObject [-Amended] [-AsJob] [-Impersonation <ImpersonationLevel>] [-Authentication <AuthenticationLevel>]
[-Locale <string>] [-EnableAllPrivileges] [-Authority <string>] [-Credential <pscredential>] [-ThrottleLimit <int>]
[-ComputerName <string[]>] [-Namespace <string>] [<CommonParameters>]

Notice the filter parameter in the first parameter set.

When you run Get-WMIObject in effect you are running a WQL query

“SELECT * FROM Win32_LogicalDisk”

if you move the filter into the query it changes to

“SELECT * FROM Win32_LogicalDisk WHERE DriveType = 3”

This is coded in the cmdlet as

Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType = 3"

Why is this better?

Because you are doing less work against the WMI repository – therefore more efficient.

Also if you are running against a remote machine filtering in the WMI query means you bring less data back across the network which makes you whole process more efficient.

Bottom line – filter as early as you sensibly can and preferably on the remote machine.

February 13, 2013  1:35 PM

PowerShell Workflow–the complete series

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

The series of articles on PowerShell workflows that are appearing on the Scripting Guy blog is now complete.

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

http://blogs.technet.com/b/heyscriptingguy/archive/2013/02/06/powershell-workflows-design-considerations.aspx

http://blogs.technet.com/b/heyscriptingguy/archive/2013/02/13/powershell-workflows-a-practical-example.aspx

The series is complete for now but as workflow is such a new topic expect more on it in the future.

Until then Enjoy!


February 5, 2013  1:45 PM

Scripting Games warm up

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

As a warm up for this years Scripting Games a two event Winter Scripting Camp has been organised.  Details from  http://powershell.org/games/


January 30, 2013  4:06 PM

PowerShell and Active Directory recording

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

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


January 30, 2013  1:10 PM

PowerShell workflows–now we are six

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

 

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!


January 28, 2013  12:16 PM

PowerShell and Active Directory–reminder

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

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


January 19, 2013  11:05 AM

Piping between functions

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

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)


January 17, 2013  1:49 PM

Starting virtual machines for WSUS

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

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.


January 17, 2013  2:26 AM

Account SIDs–hopefully my last word

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

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


January 16, 2013  4:47 PM

Account SIDs revisited

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

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


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: