PowerShell for Windows Admins


May 20, 2013  3:50 PM

Scripting Games – Win32_LogicalDisk or Win32_Volume

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

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.

May 16, 2013  12:56 PM

Scripting Games-Subfunctions

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

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.


May 14, 2013  1:22 PM

Scripting Games–filtering on remote server

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

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!


May 12, 2013  3:20 PM

Scripting games–ErrorActionPreference

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

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.


May 9, 2013  1:43 PM

Scripting Games–making work

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

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 easier to read when you come back to the script in 6 months time


May 8, 2013  1:08 PM

AD MoL Chapter 10 MEAP

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

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


May 7, 2013  3:21 PM

Scripting Games–new Get-ChildItem parameters

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

One improvement that came with PowerShell v3 is the –File and –Directory parameters on Get-ChildItem

If I run this

Get-ChildItem -Path c:\mydata

I will get a mixture of directories and files

Mode LastWriteTime Length Name
—- ————- —— —-
d—- 19/11/2012 20:19 Delivery
d—- 26/02/2013 19:24 Demo
d—- 05/05/2013 11:26 ScriptingGames 2013
d-r– 07/05/2013 18:17 SkyDrive
d—- 24/01/2013 20:08 Summit NA 2012
-a— 06/05/2013 15:26 1336320 2013May_ErrorHandling.doc

If I add the –Recurse parameter it gets worse – I know I’ve got a lot of files and directories in here.

In PowerShell v2 you could separate the directories and files by using PSISContainer

Get-ChildItem -Path c:\mydata | where {$_.PSIsContainer}
Get-ChildItem -Path c:\mydata | where {!$_.PSIsContainer}

will give you the directories only and files only respectively.

It gets easier in PowerShell v3

Get-ChildItem -Path c:\mydata -Directory
Get-ChildItem -Path c:\mydata –File

simple and obvious when you read it.

if you are using PowerShell v3 don’t forget these parameters


May 7, 2013  3:00 PM

Scripting Games-don’t repeat the work

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

There are some good features to this script but what really hurts is the two trips to the server for the Win32_Computersystem class

Foreach ($IP in (Get-Content “C:\IPList.txt”))
{
$Name = (Get-WMIObject Win32_ComputerSystem -ComputerName $ip).Name
$Mem = [math]::truncate((Get-WMIObject Win32_ComputerSystem -ComputerName $ip).TotalPhysicalMemory / 1MB)
$Ver = (Get-WMIObject Win32_OperatingSystem -ComputerName $ip).Caption
[Array]$Cpus = (Get-WMIObject Win32_Processor -ComputerName $ip)
$CpuCount = $Cpus.Count
$Cores = 0
Foreach ($Socket in $Cpus)
{
$Cores = $Cores + $Socket.NumberOfCores
}
“$Name,$Mem,$Ver,$CpuCount,$Cores” | Out-File output.csv -Append
}
it would be better to do this
$comp = Get-WMIObject Win32_ComputerSystem -ComputerName $ip
$name = $comp.Name
$mem = [math]::truncate($comp.TotalPhysicalMemory / 1MB)

Dropping one round trip on a few servers isn’t that big a deal. dropping it on 3000 servers will make a difference
Always think about how your scripts may need to scale one day


May 7, 2013  2:15 PM

Scripting Games–how not to output data

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

I haven’t finished blogging about event 1 yet but this caught my eye.

Things aren’t too bad until we hit the bunch of write-host calls

$wrks = (Get-Content -path C:\IPList.txt)
foreach ($wrk in $wrks)
{
$osver = Get-WMIObject -class win32_operatingsystem -ComputerName $wrk
$procs = @(Get-WMIObject -class win32_processor -ComputerName $wrk)
$psok=($procs.SocketDesignation).count
$pcors=(($procs.numberofcores[0])*$psok)
$plog=($pcors * 2)
$psped=$procs.MaxClockSpeed[0]
$mem = Get-WMIObject -class win32_physicalmemory -ComputerName $wrk
$memtotal = ($mem | Measure-Object -Property capacity -Sum)
$memgb = $memtotal.sum/1gb
Write-host “*******************************************************”
Write-Host “Machine Name: ” $osver.CSName
Write-Host “OS: “$osver.caption
Write-Host “Service Pack: “$osver.csdversion
Write-Host “Build #: “$osver.version
Write-Host “*********** ”
Write-Host “Memory Installed:”
Write-Host “*********** ”
Write-Host “Memory (GB): $memgb ”
Write-Host “Slots used:” $memtotal.Count
Write-Host “*********** ”
Write-Host “Processor(s) Installed:”
Write-Host “*********** ”
Write-Host “Sockets:” $psok
Write-Host “Cores:” $pcors
Write-Host “Logical Procs:” $plog
Write-Host “*********** ”
Write-Host “Processor Details:”
Write-Host “*********** ”
$procs
Write-Host “”
}

The correct way is to create an object and output that

I’ll be blogging a sample answer when the games are over. for now be aware that write-host is worse than backticks


May 6, 2013  11:53 AM

Scripting Games: event 1–use of robocopy

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

The object of the exercise in both the beginners and advanced sections of event 1 was to move a set of log files older than a give data to an archive folder.

A number of solutions were presented that used robocopy.

This is a workable solution that meets the lettter of the objective but it doesn’t really meet the spirit of the games.

The Scripting Games is about learning to use PowerShell. Within PowerShell there is a move-item cmdlet.

Robocopy isn’t required. Using non-Powershell tools can often be harder than using PowerShell. In your work, and especially in the games, think very carefully before reaching for a non-PowerShell command


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: