Categories

Monthly Archives: May 2013

Scripting Games-Voting

Still time to vote on event 4 – the numbers of votes are falling off slightly – especially in the Advanced events. This is your opportunity to observe what other people are doing, comment and very possibly learn.

PowerShell Deep Dive–MEAP now complete

The final chapters of PowerShell Deep Dive have been added to the MEAP

http://www.manning.com/hicks/

Enjoy

AD Month of Lunches–Chapter 11 in MEAP

The MEAP for AD Management in a Month of Lunches has been extended with the inclusion of chapter 11 – Creating Domain Controllers.

www.manning.com/siddaway3

Enjoy

Scripting Games – Filter early again

Grading the scripts in Event 4 and the one thing that jumps out is the amount of unnecessary data being carried through the scripts

You were asked for 7 properties off 20 random users

Get-ADUser has a –properties parameter. USE it to restrict the properties you return. You don’t NEED all the other properties

Next select you 20 users as soon as possible

get-aduser | get-random

will do that.  You can then format just the few properties you need on the 20 objects you have left

FILTER EARLY

Scripting Games – Win32_LogicalDisk or Win32_Volume

I have heard some discussions recently regarding whether Win32_LogicalDisk or Win32_Volume should be used in the answer to event 3 in the Scripting Games.

The problem requires you pull the drive letter, drive size and freespace for local disks on the server. Notice the emphasis – that will be important.

Looking at Win32_Volume

PS> Get-CimClass -ClassName Win32_Volume | select -ExpandProperty CimClassproperties  | select Name

Name
----
Caption
Description
InstallDate
Name
Status
Availability
ConfigManagerErrorCode
ConfigManagerUserConfig
CreationClassName
DeviceID
ErrorCleared
ErrorDescription
LastErrorCode
PNPDeviceID
PowerManagementCapabilities
PowerManagementSupported
StatusInfo
SystemCreationClassName
SystemName
Access
BlockSize
ErrorMethodology
NumberOfBlocks
Purpose
Automount
BootVolume
Capacity
Compressed
DirtyBitSet
DriveLetter
DriveType
FileSystem
FreeSpace
IndexingEnabled
Label
MaximumFileNameLength
PageFilePresent
QuotasEnabled
QuotasIncomplete
QuotasRebuilding
SerialNumber
SupportsDiskQuotas
SupportsFileBasedCompression
SystemVolume

You see 3 properties that might be of use

Get-CimInstance -ClassName Win32_Volume | select DriveLetter, Capacity, FreeSpace

is a start but I get two drives with no capacity & freespace – must by my DVD drives

I can filter those out using drive type.  DriveType =3 gives me local disks

So the WMI call I need is

Get-CimInstance -ClassName Win32_Volume -Filter "DriveType=3"  | select DriveLetter, Capacity, FreeSpace

Get-WmiObject -Class Win32_Volume -Filter "DriveType=3"  | select DriveLetter, Capacity, FreeSpace

 

Now lets look at Win32_LogicalDisk

PS> Get-CimClass -ClassName Win32_Logicaldisk | select -ExpandProperty CimClassproperties  | select Name

Name
----
Caption
Description
InstallDate
Name
Status
Availability
ConfigManagerErrorCode
ConfigManagerUserConfig
CreationClassName
DeviceID
ErrorCleared
ErrorDescription
LastErrorCode
PNPDeviceID
PowerManagementCapabilities
PowerManagementSupported
StatusInfo
SystemCreationClassName
SystemName
Access
BlockSize
ErrorMethodology
NumberOfBlocks
Purpose
FreeSpace
Size
Compressed
DriveType
FileSystem
MaximumComponentLength
MediaType
ProviderName
QuotasDisabled
QuotasIncomplete
QuotasRebuilding
SupportsDiskQuotas
SupportsFileBasedCompression
VolumeDirty
VolumeName
VolumeSerialNumber

 

I can’t find a DriveLetter but I know that DeviceId supplies that information – if in doubt check by displaying all properties of one instance or do this

PS> Get-CimInstance -ClassName Win32_Logicaldisk | ft -a

DeviceID DriveType ProviderName VolumeName      Size         FreeSpace
-------- --------- ------------ ----------      ----         ---------
C:       3                                      249951154176 146292559872
D:       3                      System Reserved 104853504    69279744
E:       2
F:       5

Drivetype matches with Win32_Volume so we get

Get-CimInstance -ClassName Win32_Logicaldisk | Select Deviceid, Size, FreeSpace
Get-WmiObject -Class Win32_Logicaldisk | Select Deviceid, Size, FreeSpace

You’ll have noticed that D: has a volume name of System Reserved. This means its a system disk that you shouldn’t be touching. Technically the event asked for information on local disks so it should be included. I know that some purists will argue against this so to remove the system volume you can

PS>  Get-CimInstance -ClassName Win32_Volume -Filter "DriveType=3 AND SystemVolume = $false"  | select DriveLetter, Capacity, FreeSpace

or

PS> Get-CimInstance -ClassName Win32_Logicaldisk -Filter "DriveType = 3 AND VolumeName <> 'System Reserved'" | select DeviceId, Size, FreeSpace

 

So either will give you the results you need.  You just need to dig into the classes a bit.

Scripting Games-Subfunctions

One of the principles of writing scripts (or any code) is the KISS principle – Keep It Simple Scripter.

That principle is being abused al lot in event 3

I am seeing numerous entries that define an advanced function as the solution and then inside the PROCESS block define one or more functions.  You PROCESS block is executed once for EVERY object on your pipeline. For 1 object might not matter but for 100s of objects it will adversely affect performance.

The solutions are such that they sensibly fit in a single solution.  If you must define additional functions make the solution a module so you only load them once.

Scripting Games–filtering on remote server

In event 3 you have to get information on hard disk capacity.  I’ve only looked at the first couple of dozen scripts but seen this too many times

Get-WmiObject -Class Win32_LogicalDisk | where DriveType -eq 3

or if you prefer the version 2 way

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

If puppies get terminated for using Write-Host this sort of construct should triggers a mass extinction.

When pulling information back with WMI (or any other technique) from a remote server ALWAYS, ALWAYS, ALWAYS filter on the remote server.  What you are doing here is pulling back all of the data and filtering on the client. This is grossly inefficient when you are dealing with hundreds of machines.

The PowerShell team gave us the –Filter parameter on Get-WmiObject for a reason. Its to do the filtering on the remote server.

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

If you are guilty of not using –Filter write out 100 times “I must filter on the remote server”

And no – you can’t write a PowerShell script to do it for you!

Scripting games–ErrorActionPreference

I’ve seen a lot of this type of thing in events 1 and 2

$ErrorPref = $ErrorActionPreference
$ErrorActionPreference = "Stop"

 

Don’t

The default for $ErrorActionPreference is Continue.  This means that the error message is shown and the cmdlet attempts to continue. The possible values (from about_Preference_Variables)


Stop:               Displays the error message and stops  executing.

Inquire:            Displays the error message and asks you  whether you want to continue.

Continue:           Displays the error message and continues executing.
(Default)          

SilentlyContinue:   No effect. The error message is not displayed and execution continues without interruption.

This preference variable only affects non-terminating errors. A terminating error will still stop processing.  Using

$ErrorActionPreference = "Stop"

effectively turns all errors in to terminating errors.

There are times when you want to stop processing and deal with the error such as

try {

some cmdlet

}

catch {

do something

}

In this case use –ErrorAction Stop  on the cmdlet to force errors to be terminating. Just makes sure you have the code in place to catch the error.

Scripting Games–making work

I saw this in one of the submissions:

$Properties = @{}
$Properties['Computer'] = $SystemInfo.__SERVER
$Properties['OperatingSystem'] = "$($OSInfo.Caption) - $($OSInfo.CSDVersion)"
$Properties['PhysicalMemory'] = $SystemInfo.TotalPhysicalMemory  

My immediate thought was the entrant likes making work for themselves. The hash table can be created in a much simpler manner

$Properties = @{
Computer = $SystemInfo.__SERVER
OperatingSystem = "$($OSInfo.Caption) - $($OSInfo.CSDVersion)"
PhysicalMemory = $SystemInfo.TotalPhysicalMemory
}

Same result. Less typing and easiert o read when you come back to the script in 6 months time

AD MoL Chapter 10 MEAP

Chapter 10 of AD Management in a Month of Lunches is now available.

http://www.manning.com/siddaway3/

The chapter covers Fine Grained Password Policies