Wednesday, September 28, 2022
HomePowershellThe Worth of Objects • The Lonely Administrator

The Worth of Objects • The Lonely Administrator


It is a reprint of an article revealed earlier this yr in my premium PowerShell publication, Behind the PowerShell Pipeline. It is a pattern of what my subscribers get 6-8 instances a month.

I anticipate I’ll write a number of articles about PowerShell and its relationship with objects. I do know that that is the most important hurdle for PowerShell newbies to beat. However as soon as they grasp that PowerShell is about working with objects within the pipeline, they acknowledge the worth and start discovering it simpler to put in writing PowerShell code and use it interactively at a console immediate.

Handle and Report Energetic Listing, Alternate and Microsoft 365 with
ManageEngine ADManager Plus – Obtain Free Trial

In a Console A Lengthy, Lengthy Time In the past

Don’t neglect that I’m approaching PowerShell from the function of an IT professional. Many of those individuals come to PowerShell with different automation and scripting expertise. It may be old school batch information. It may be in depth expertise with VBScript. That was my PowerShell journey. Like a lot of you, my preliminary PowerShell experiences have been coloured by my previous. I stored attempting to make PowerShell write textual content as I did with VBScript. Right here’s an previous instance.

Dim objSet, wshell
On Error Resume Subsequent

Set wshell=CreateObject("Wscript.Shell")

If wscript.arguments.rely=0 Then
 strSrv=InputBox("What server do you wish to verify?  You need to have admin rights on it.  Do NOT use  " & _
 "earlier than the servername.","Disk Test","SERVERNAME")
 If strSrv="" Then
   wshell.popup "Nothing entered otherwise you cancelled",4,"Disk Test",0+48
   wscript.give up
 Finish If
Else
 strSrv=Trim(wscript.arguments(0))
Finish If

strQuery = "Choose * from win32_logicaldisk the place drivetype=3"
Set objSet=GetObject("winmgmts:" & strSrv).ExecQuery(strQuery)
if err.quantity<>0 then
 wshell.popup "Oops! Error connecting to " & UCase(strSrv) & vbCrlf & "be sure you are utilizing legitimate " & _
 "credentials." & vbCrlf & "Error: " & err.quantity & " - " & err.description,5,"Disk Test Error",0+48
 wscript.give up
finish if

For Every merchandise In objSet
   PerFree=FormatPercent(merchandise.FreeSpace/merchandise.Measurement,2)
   o=o & merchandise.DeviceID & "" & VBTAB
   o=o & FormatNumber(merchandise.Measurement/1048576,0) & Vbtab & FormatNumber(merchandise.FreeSpace/1048576,0) & Vbtab & PerFree & Vbcrlf
subsequent
WScript.Echo "Drive" & Vbtab & "Measurement (MB) Free (MB) %Free" & VbCrLf & o
set objSet=Nothing
set wshell=Nothing

wscript.give up

Don’t panic. I’m not going to try to train you VBScript. The script is getting disk data from WMI and displaying a abstract. However to get the specified outcome, I spend lots of time creating strings of textual content to show. Within the For Every merchandise part, I’m constructing a string for every drive displaying the dimensions and free area. Every drive  will get concatenated to the variable o. On the finish of the script, I write the string of knowledge to the display screen.

WScript.Echo "Drive" & Vbtab & "Measurement (MB) Free (MB) %Free" & VbCrLf & o

Right here’s what I find yourself with.

Many individuals new to PowerShell are attempting to drive it to behave like this. They’re used to a scripting language returning a string of textual content. That is very true of individuals with a background in Linux bash scripting. As a result of Linux is a text-based working system, its instruments are primarily based on the idea of parsing textual content. Somebody new to PowerShell and nonetheless caught within the textual content paradigm would possibly write a PowerShell script like this.

$strSrv = Learn-Host "Enter a computername"
$strQuery = "Choose * from win32_logicaldisk the place drivetype=3"
$objSet = Get-WmiObject -Question $strQuery -ComputerName $strSrv
Write-Host "Drive`t Measurement (MB)       Free (MB)       %Free"
foreach ($merchandise in $objSet) {
$perFree = ($merchandise.FreeSpace/$merchandise.dimension)*100
$line = $merchandise.DeviceID + "   `t" + $merchandise.Measurement/1048576 + "  " + $merchandise.FreeSpace/1048576 + "  " + $perFree
Write-Host $line
}

Sadly, I’ve seen code like this in the true world. It can work. Kind of.

vbscript as powershell

However this can be a lot of labor. One motive individuals get hung up on textual content is that operating a command in PowerShell nearly at all times produces easy-to-read textual content output. Consider the outcome you get from Get-Service and Get-Course of.

Objects Are Straightforward

The concept of an object shouldn’t be that tough. We cope with objects in the true world day-after-day. The problem is getting our heads wrapped across the idea of digital objects. For those who take the time to have a look at PowerShell, you’ll see it’s attempting that will help you. The command names suggest objects. Get-Service goes to get service objects. Right here’s a state of affairs the place utilizing the total cmdlet title as a substitute of the gsv alias will help a newbie. You don’t wish to be taught PowerShell pondering, “Once I run the gsv command, I get an inventory of providers.” You wish to be pondering, “Once I run the Get-Service command, I get a group of service objects that I can cross on to a different command.”

Let’s revisit the WMI code. The code says, “Get me a WMI object that could be a Win32_Logicialdisk that meets particular standards on the required distant pc.” As soon as these objects have been returned, the code tells PowerShell what object properties to show. The outcomes are displayed, and PowerShell routinely handles the entire formatting.

$computername  = Learn-Host "Enter a computername"
$Question = "Choose * from win32_logicaldisk the place drivetype=3"
Get-WmiObject -Question $Question -ComputerName $computername | 
Choose-Object -property DeviceID,Measurement,Freespace,
@{Title="PercentFree";Expression = {$_.freespace/$_.dimension}}
formatted results in PowerShell

Probably the greatest options of PowerShell is that you would be able to additionally outline new object properties. The WMI win32_logicaldisk object doesn’t have a PercentFree property. However Choose-Object can do this for me with the customized hashtable.

When you begin serious about objects and never parsing textual content, you’ll understand there’s a whole world of potentialities. I inform starting PowerShell scripters to say aloud what they need PowerShell to do.

Get all fastened logical disks from a distant pc. Choose the pc title, drive letter, dimension in GB, free disk area, and p.c free area and export to a CSV file.

When you articulate what you need, you’ll find the PowerShell instructions and parameters to make it occur.

Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" -ComputerName $computername |Choose-Object -property DeviceID,@{Title="SizeGB";Expression = {$_.dimension/1GB -as [int32]}},Freespace,@{Title="PercentFree";Expression = {($_.freespace/$_.dimension)*100}},SystemName |Export-CSV c:workdiskinfo.csv -Append

The most important hurdle for newbies is discovering object properties with Get-Member and the methods to format values, corresponding to utilizing the 1GB shortcut and the -As operator. I’ve discovered that the individuals who can visualize the idea of objects within the pipeline undertake PowerShell faster and with much less ache.

That’s to not say we nonetheless don’t have to mess with textual content or values. The p.c free worth I outlined above is a  good instance. You may be inclined to make use of the -f operator.

@{Title="PercentFree";Expression = {"{0:p2}" -f ($_.freespace/$_.dimension)}}

It certain appears to be like good.

formatted percentages

If all I wish to do is take a look at this outcome, I may be okay. However even right here, we’re again to textual content. If I pipe this output to Get-Member I’ll see that the PercentFree property is a System.String. The issue arises once I wish to do one thing with the worth, corresponding to sorting. The worth will kind as a string, not a quantity, and I won’t get the anticipated outcomes.

I discover a higher method is to deal with the worth as a [System.Double] object utilizing the [math] class to spherical the worth to 2 decimal locations.

@{Title="PercentFree";Expression = {[math]::spherical(($_.freespace/$_.dimension)*100,2)}}

With this, I get the formatted share I need and a worth I can use.

I hope you may see the worth right here.

Features Write Objects

The final a part of the story I wish to talk about briefly revolves round PowerShell capabilities. I’ve very robust opinions on methods to write a PowerShell operate correctly and the way it ought to behave. That is usually at odds with individuals who come to PowerShell with a developer background or possibly used to writing VBScript subroutines.

Whereas I acknowledge there are exceptions, a PowerShell operate ought to write a sequence of objects, or possibly a single object, to the pipeline. It isn’t returning something that appears like a string. Technically, there’s nothing improper with this straightforward PowerShell operate.

Perform Get-PercentFree {
    Param($Drive = "C:", $Computername = $env:COMPUTERNAME)

    $d = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DeviceID='$Drive'" -ComputerName $computername
    $p = [math]::spherical(($d.freespace / $d.dimension) * 100, 2)
    return $p
}

However it’s of restricted worth. All I’m going to get is a outcome like 40.96. I’d have written this kind of code as a VBScript subroutine. However we’re speaking about PowerShell. I need an object within the pipeline.

Perform Get-LogicalDisk {
    [cmdletbinding()]
    Param($Computername = $env:COMPUTERNAME)

    $disks = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" -ComputerName $computername
    $disks | Choose-Object @{Title = "Computername"; Expression = { $_.SystemName } },
    DeviceID, Measurement, FreeSpace, @{Title = "PercentFree"; Expression = { [math]::spherical(($_.freespace / $_.dimension) * 100, 2) } },
    @{Title = "Audit"; Expression = { Get-Date } }
}

The operate is written to make some extent, not essentially one thing prepared for manufacturing. Operating the operate offers this type of output.

get logical disk objects

If all I would like is p.c free, that’s simple sufficient to retrieve.

getting drive usage with PowerShell

The operate is versatile and re-usable as a result of it writes a wealthy object to the pipeline.

For those who observed within the operate, I additionally didn’t format the dimensions and free area values. I left them in bytes. Getting or creating an object in PowerShell is separate from how it’s formatted or offered. However that’s a subject for an additional day.

If I would like strings, say for a log file, I can nonetheless create them from objects.

$information = "prospero","thinkx1-jh","dom1","srv2" | 
Foreach-Object { Get-LogicalDisk -Computername $_ }
foreach ($merchandise in $information) {
 $line = "[{0:d}] Drive {1} on {2} is {3}% free" -f $merchandise.Audit,$merchandise.DeviceID,$merchandise.computername,$merchandise.percentfree
 $line
 #$line | Out-File log.txt -append
}

Word that as a result of the Audit property is a datetime object, I can format it utilizing the d qualifier.

text from objects

Attempting to perform this with a text-based paradigm is way more difficult and irritating.

The extra you concentrate on the thing you may get from PowerShell and the way you need to use it, the extra you may accomplish, and probably with higher PowerShell code.


Learn PowerShell Scripting in a Month of Lunches, 2nd Ed. MEAP


RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments