PowerShell in Practice ebook deal
Posted by: Richard Siddaway
I know there isn’t much of today left but if you are quick its possible to get an ebook version of PowerShell in Practice for $15. See the deal of the day at http://www.manning.com/
I know there isn’t much of today left but if you are quick its possible to get an ebook version of PowerShell in Practice for $15. See the deal of the day at http://www.manning.com/
One of the things I noticed in the recent Scripting Games was that a lot of the scripts would do things like this
$query = "Select MaxClockSpeed from Win32_Processor"
$proc = Get-WmiObject -Query $query
Write-Host "Speed: " $proc.MaxClockSpeed
Create a query to access the Win32_Processor class to get the MaxClockSpeed. Run the query and then use Write-Host to format and output the results. We’ll come back to use Write-Host like this another time.
This construction is based on the way things used to be done with VBScript. With PowerShell we have much easier ways to get to the same result.
Get-WmiObject -Class Win32_Processor | Format-List MaxClockSpeed
will produce the same answer. if you really need the formatting
Get-WmiObject -Class Win32_Processor | Format-List @{Name=’Speed’; Expression={$_.MaxClockSpeed}}
or even
Write-Host "Speed: " (Get-WmiObject -Class Win32_Processor).MaxClockSpeed
Get-WmiObject does a great job of returning the information from a WMI class. Use its power and simplicity to make your scripts quicker to write and easier to understand
If you’ve used ping before you’ll know that it normally returns four replies from the target. In PowerShell we have Test-Connection which does the same job. It also normally returns four replies.
When I’m working with remote machines I often want to check they are available before sending a command – especially a WMI command that can take a long time to time out.
|
001
002 003 004 005 006 007 008 |
"rslaptop01", "127.0.0.1" |
foreach { if (Test-Connection $_ -Count 1) { Get-WmiObject -ComputerName $_ -Class Win32_LogicalDisk ` -Filter "DriveType=’3′" | select SystemName, DeviceID, Size, FreeSpace } } |
To speed up the process use the –Count parameter on test-connection and only get 1 reply. Quick test to see if he system is there and then run the rest of the code
Thank you to everyone who joined the Live Meeting this evening. Hope you enjoyed the session on PowerShell events.
The slides and demo files are available from
http://cid-43cfa46a74cf3e96.skydrive.live.com/browse.aspx/PowerShell%20User%20Group/May%202010
The recording can be viewed on line
View Recording
Recording Details
Subject: PowerShell Events
Recording URL: https://www.livemeeting.com/cc/usergroups/view
Recording ID: 39Q7T9
Attendee Key: Q&x!_63dP
PowerShell in Practice will be going to the printers next week.
Between now and 21 May 2010 you can get 40% off of PowerShell in Practice (and other Manning books that are in the final stages of production)
Use promotional code m1440 at checkout from www.manning.com
We can use WMI to access the registry on local and remote machines – if you remember back to VBScript it was the way to access the registry.
In PowerShell we have a couple of PowerShell drives available through the provider
Name Used (GB) Free (GB) Provider Root
—- ——— ——— ——– —-
HKCU Registry HKEY_CURRENT_USER
HKLM Registry HKEY_LOCAL_MACHINE
These only work with the local machine. We can use PowerShell remoting to access the registry but if PowerShell isn’t installed we are back to WMI.
The class we need to use is StdRegprov
In Windows XP\2003 and earlier it is only found in the root\default namespace. In Windows Vista\2008 and above it is also found in the root\cimv2 namespace (which is the default namespace PowerShell uses). In order to access most machines we will work with the root\default instance. We need to use the [wmiclass] type accelerator
$reg = [wmiclass]\\.\root\default:StdRegprov
looking at $reg though get-member we see a lot of methods
CheckAccess
CreateKey
DeleteKey
DeleteValue
EnumKey
EnumValues
GetBinaryValue
GetDWORDValue
GetExpandedStringValue
GetMultiStringValue
GetQWORDValue
GetSecurityDescriptor
GetStringValue
SetBinaryValue
SetDWORDValue
SetExpandedStringValue
SetMultiStringValue
SetQWORDValue
SetSecurityDescriptor
SetStringValue
We will start looking at these next time
String substitution is one of my favourite bits of PowerShell. If you’ve not seen it before the idea is that you can substitute a variable into a double quoted string. Note that single quote strings won’t work. As an example
PS> $colour = "red"
PS> "The balloon is $colour"
The balloon is red
PS> ‘The balloon is $colour’
The balloon is $colour
One place this breaks down in when substituting properties of an object. Consider something we’ve pulled back with WMI.
PS> $os = Get-WmiObject -Class Win32_OperatingSystem
PS> $os
SystemDirectory : C:\Windows\system32
Organization :
BuildNumber : 7600
RegisteredUser : Richard
SerialNumber : 00426-065-1155216-86852
Version : 6.1.7600
We can pick off a couple of properties
PS> $os | select Caption, ServicePackMajorVersion | Format-List
Caption : Microsoft Windows 7 Ultimate
ServicePackMajorVersion : 0
We can use write-host
PS> Write-Host $os.Caption, $os.ServicePackMajorVersion
Microsoft Windows 7 Ultimate 0
and even expand it a bit
PS> Write-Host $os.Caption, "Service Pack", $os.ServicePackMajorVersion
Microsoft Windows 7 Ultimate Service Pack 0
but if we try string substitution
PS> Write-Host "The OS is $os.Caption with Service Pack $os.ServicePackMajorVersion"
The OS is \\RSLAPTOP01\root\cimv2:Win32_OperatingSystem=@.Caption with Service Pack \\RSLAPTOP01\root\cimv2:Win32_OperatingSystem=@.ServicePackMajorVersion
Oops – thats not what we want
The problem is that we are getting the object rather than the value. We need to use a subexpression
PS> Write-Host "The OS is $($os.Caption) with Service Pack $($os.ServicePackMajorVersion)"
The OS is Microsoft Windows 7 Ultimate with Service Pack 0
All this does is say give me the result of the expression in the brackets and substitute that in the string. Easy and neat. No need to concatenate strings to create the display line in your scripts.
When: Tuesday, May 18, 2010 7:30 PM (BST) Where: Live Meeting *~*~*~*~*~*~*~*~*~*
PowerShell eventing using WMI, .NET and the PowerShell engine
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:
https://www.livemeeting.com/cc/usergroups/join
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.
If you’ve used VBScript in the past you will remember using Win32_PingStatus to test the connectivity to a remote machine. In the 2010 Scripting Games we’ve seen a lot of scripts testing if a remote machine can be contacted.
Many of the scripts contain code of the form
$query = "Select * from Win32_PingStatus WHERE Address = ’127.0.0.1′"
Get-WmiObject -Query $query
There’s nothing wrong with this and it does the job so any marks for testing remote connectivity will be awarded. This code is a direct translation of the VBScript code.
The query could be given as part of the call to Get-WmiObject bit we can make it easier by doing this:
Get-WmiObject -Class Win32_PingStatus -Filter "Address = ’127.0.0.1′"
The query after the WHERE statement becomes the filter and we give the class directly. Bit less typing and easier to read.
if we want this as part of a loop where we will be testing multiple machines then we can refine it to this
$computer = ’127.0.0.1′
Get-WmiObject -Class Win32_PingStatus -Filter "Address = ‘$computer’"
The $computer variable could be set as part of the loop control rather than as a direct variable. One thing to be aware of is that computername parameter isn’t supported in the way most WMI classes support it
Note that this is NOT supported
Get-WmiObject -Class Win32_PingStatus -ComputerName $computer
In PowerShell v2 it gets even simpler as we have a cmdlet that wraps Win32_PingStatus for us
Test-Connection -ComputerName $computer
but it returns four pings by default so use
Test-Connection -ComputerName $computer -Count 1
All of the above work but the last one is the easiest and involves least typing (remember tab completion)
In this post http://itknowledgeexchange.techtarget.com/powershell/current-logged-on-user/ we discovered how to find the current logged on user. I want to extend that a bit and add the information about that users desktop.
We start with the script in our earlier post.
|
001
002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 |
## get session process
$proc = Get-WmiObject -Class Win32_SessionProcess | select Antecedent -First 1 $filt = ($proc -split "=")[2] -replace ‘"’,” -replace "}","" $ltype = DATA { ## get user $query2 = "ASSOCIATORS OF {Win32_UserAccount.Domain=’$($user.Domain)’" ` $desktop = Get-WmiObject -Query $query2 |
We add a query to get the desktop associated with the current user – - $query2
That query returns the information about the desktop. Its displayed after the user information and I’ve selected the items I want to display.
This is a good example of extending an existing script when you find out how to do a bit more digging.
I think we’ve about exhausted the WMI information on users and groups for now – so its time to find another topic.
