May 13, 2012 10:34 AM
Posted by: Richard Siddaway
Network,
PowerShell,
WMIA question on the forum got me wondering about setting the Alternative Configuration on a TCP/IP properties of a network adapter. NICs are normally configured to either DHCP or a static address. If you use DHCP another tab “Alternative Configuration” appears on the IPv4 properties dialog. This can be set to APIPA (an address in the range 169.254.x.x/16 – ie DHCP failed) or a static address. DHCP will be tried first and if it fails the Alternative Configuration kicks in.
I had never seen anything on configuring this so started to dig.
It turns out that the information is held in the registry – big surprise! The data is a little difficult to track down
## http://technet.microsoft.com/en-us/library/bb457118.aspx
$index = 7
$HKLM = 2147483650 #HKEY_LOCAL_MACHINE
$data = @{}
$nic = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "Index=$index"
$key = "SYSTEM\CurrentControlSet\services\Tcpip\Parameters\Interfaces\$($nic.SettingID)"
$rc = Invoke-WmiMethod -Class StdRegProv -Name EnumValues -ArgumentList $hklm, $key
if ($rc.ReturnValue -eq 0) {
$num = $rc.Types.count -1
for ($i=0; $i -le $num; $i++){
switch ($rc.Types[$i]) {
1 {$value = Invoke-WmiMethod -Class StdRegProv -Name GetStringValue -ArgumentList $hklm, $key, $($rc.sNames[$i]) | select -ExpandProperty sValue}
2 {$value = Invoke-WmiMethod -Class StdRegProv -Name GetExpandedStringValue -ArgumentList $hklm, $key, $($rc.sNames[$i]) | select -ExpandProperty sValue}
3 {$value = Invoke-WmiMethod -Class StdRegProv -Name GetBinaryValue -ArgumentList $hklm, $key, $($rc.sNames[$i]) | select -ExpandProperty uValue}
4 {$value = Invoke-WmiMethod -Class StdRegProv -Name GetDWORDValue -ArgumentList $hklm, $key, $($rc.sNames[$i]) | select -ExpandProperty uValue}
7 {$value = Invoke-WmiMethod -Class StdRegProv -Name GetMultiStringValue -ArgumentList $hklm, $key, $($rc.sNames[$i]) | select -ExpandProperty sValue}
default {Write-Warning "Could not process $($rc.sNames[$i]) - type $($rc.Types[$i])"}
}
$data += @{$($rc.sNames[$i]) = $value}
} ## end for
}
else {
Write-Error "WMI call to registry provider failed"
}
$data.GetEnumerator() | sort key
I’ve cheated for now and defined the NIC I’m interested in – Index =7 is my LAN connection.
I need to work with the HKLM hive so define the appropriate constant.
After getting the WMI object for the NIC – filter on Index I use the SettingID to define the registry key I need. The settingID looks like this – {01F4E3B7-5F1F-40BD-8252-DCC3331891C1}
The EnumValues method gives me the registry value names and types for that key. I can loop through them and call the appropriate method to read the registry value.
The data is output sorted by value name and looks like this
Name Value
—- —–
AddressType 0
DefaultGateway
DefaultGatewayMetric
DhcpConnForceBroadcastFlag 0
DhcpGatewayHardware {192, 168, 1, 1…}
DhcpGatewayHardwareCount 1
DhcpInterfaceOptions {6, 0, 0, 0…}
DhcpServer 255.255.255.255
Domain
EnableDeadGWDetect 1
EnableDHCP 0
IPAddress 10.10.54.202
IsServerNapAware 0
Lease 0
LeaseObtainedTime 1336923004
LeaseTerminatesTime 2147483647
NameServer 10.10.54.201
RegisterAdapterName 0
RegistrationEnabled 1
SubnetMask 255.255.255.0
T1 1336923004
T2 1336923004
UseZeroBroadcast 0
This shows we have a static address – the fact that IPAddress is set and that EnableDHCP=0
Next time we will look at enabling DHCP and then setting the alternative configuration
May 13, 2012 6:54 AM
Posted by: Richard Siddaway
PowerShell,
User GroupA number of the recent UK PowerShell group sessions are available as recordings for download. The slides and demo scripts are usually included in the download package. They can be downloaded from mu skydrive under the PowerShell User group folder.
https://skydrive.live.com/#cid=43CFA46A74CF3E96&id=43CFA46A74CF3E96%212469
The following sessions are available
2011 09 PowerShell remoting and end point customisation
2011 11 Whats new in PowerCLI 5
2011 12 Intro to WMI
2011 12 WSMAN_WMI_and_CIM
2012 January PowerShell v3 CTP 2 overview
2012 February PowerShell and SQL Server
2012 March CIM cmdlets
2012 April Powershell in Windows Server 8
This list will be updated periodically
Enjoy
May 8, 2012 1:22 PM
Posted by: Richard Siddaway
PowerShellThere are a few comments to make about using the pipeline but one of the obvious issues I saw from the games was this type of approach
$p = Get-Process
$p | where {$_.Name -like "powershell*"}
The only time this is valid is if you need to access exactly the same data later in your script.
In all other cases use
Get-Process | where {$_.Name -like "powershell*"}
if you want to split the lines to make it more readable the pipe symbol acts as a line continuation character so
Get-Process |
where {$_.Name -like "powershell*"}
is just as valid
PowerShell is all about the pipeline – use it to your advantage
May 8, 2012 12:00 PM
Posted by: Richard Siddaway
PowerShell 3,
User Group
When: Tuesday, May 29, 2012 7:30 PM (BST)
Where: Virtual
*~*~*~*~*~*~*~*~*~*
This is the second of two meetings dealing with the new PowerShell functionality in Windows Server 8
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:
- Copy this address and paste it into your web browser:
https://www.livemeeting.com/cc/usergroups/join
- Copy and paste the required information:
Meeting ID: C5C7CT
Entry Code: P[h/PKJ’7
Location: https://www.livemeeting.com/cc/usergroups
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.
May 7, 2012 10:31 AM
Posted by: Richard Siddaway
PowerShellThere are a number of ways to pass the names of the local machine into a script or function:
- use the actual name
- use the IP address (if the processing in the script can work with IP addresses)
- use 127.0.0.1 – the loop back address (if the processing in the script can work with IP addresses)
- use a dot “.” to signify the local machine
- use “localhost”
- use the environmental variable holding the machine name
Normally we don’t use any of the first three because you either have to type out the name – chance of error or the functionality within the script won’t accept IP addresses. Also the PSsession cmdlets only use computer names by default
Traditionally we have used . or localhost especially when working with WMI
Get-WmiObject -Class Win32_OperatingSystem -ComputerName .
Get-WmiObject -Class Win32_OperatingSystem -ComputerName localhost
There are a number of cmdlets that will accept a computer name as a parameter
PS> Get-Help * -Parameter ComputerName | select name
Name
—-
Get-WinEvent
Get-Counter
Test-WSMan
Invoke-WSManAction
Connect-WSMan
Disconnect-WSMan
Get-WSManInstance
Set-WSManInstance
Remove-WSManInstance
New-WSManInstance
Invoke-Command
New-PSSession
Get-PSSession
Remove-PSSession
Receive-Job
Enter-PSSession
Get-EventLog
Clear-EventLog
Write-EventLog
Limit-EventLog
Show-EventLog
New-EventLog
Remove-EventLog
Get-WmiObject
Invoke-WmiMethod
Get-Process
Remove-WmiObject
Register-WmiEvent
Get-Service
Set-Service
Set-WmiInstance
Get-HotFix
Test-Connection
Restart-Computer
Stop-Computer
This works:
Get-Process -ComputerName .
but this throws an error
PS> Get-Process -ComputerName localhost
Get-Process : Couldn’t connect to remote machine.
At line:1 char:12
+ Get-Process <<<< -ComputerName localhost
+ CategoryInfo : NotSpecified: (:) [Get-Process], InvalidOperationException
+ FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.PowerShell.Commands.GetProcessCommand
I’ve seen similar errors with Get-Eventlog
PS> Get-EventLog -List -ComputerName .
Max(K) Retain OverflowAction Entries Log
—— —— ————– ——- —
20,480 0 OverwriteAsNeeded 21,814 Application
512 7 OverwriteOlder 0 DemoMate
20,480 0 OverwriteAsNeeded 0 HardwareEvents
512 7 OverwriteOlder 0 Internet Explorer
20,480 0 OverwriteAsNeeded 0 Key Management Service
8,192 0 OverwriteAsNeeded 3 Media Center
512 7 OverwriteOlder 0 MyNewLog
128 0 OverwriteAsNeeded 357 OAlerts
20,480 0 OverwriteAsNeeded 1 Scripts
Security
20,480 0 OverwriteAsNeeded 56,225 System
15,360 0 OverwriteAsNeeded 10,646 Windows PowerShell
PS> Get-EventLog -List -ComputerName localhost
Get-EventLog : The network path was not found.
At line:1 char:13
+ Get-EventLog <<<< -List -ComputerName localhost
+ CategoryInfo : NotSpecified: (:) [Get-EventLog], IOException
+ FullyQualifiedErrorId : System.IO.IOException,Microsoft.PowerShell.Commands.GetEventLogCommand
My solution and recommendation is to use the environmental variable for the computer name.
PS> Get-ChildItem -Path env: | where {$_.name -like "*computer*"}
Name Value
—- —–
COMPUTERNAME RSLAPTOP01
The environment provider doesn’t allow the use of filters so we have to use where
How do we use this:
Get-WmiObject -Class Win32_OperatingSystem -ComputerName $env:COMPUTERNAME
Get-Process -ComputerName $env:COMPUTERNAME
Get-EventLog -List -ComputerName $env:COMPUTERNAME
It can also be used as the default value on a function parameter that asks for a computername – that way you get the local machine if you don’t specify a value to the parameter.
I have never seen this fail – doesn’t mean it can’t just that I’ve never seen it – and it has the advantage of being easier to read than using a dot
May 6, 2012 8:00 AM
Posted by: Richard Siddaway
PowerShell,
WMIIn one of the events you had to find the default printer. This can be done using WMI.
The full list of printers can seen using:
Get-WmiObject -Class Win32_Printer
If you want to examine the printer objecy – to determine what information is available – use get-member or select the first printer in the list
Get-WmiObject -Class Win32_Printer | select -f 1 | fl *
you will see that there is a property Default
PS> Get-WmiObject -Class Win32_Printer | Get-Member Default
TypeName: System.Management.ManagementObject#root\cimv2\Win32_Printer
Name MemberType Definition
—- ———- ———-
Default Property System.Boolean Default {get;set;}
which is Boolean i.e. it has to return true or false
Your first thought might ne to do this:
Get-WmiObject -Class Win32_Printer | where {$_.Default -eq $true}
but it would be better coding practice to do this:
Get-WmiObject -Class Win32_Printer | where {$_.Default}
On the local machine this is OK but if you are working remotely than all of the Win32_Printer objects would be returned and the filtering performed locally. Could be an expensive operation.
The better option is to use the –Filter parameter on Get-WmiObject
Get-WmiObject -Class Win32_Printer -Filter "Default = $true"
this only returns a single object
If you want to use WQL then it becomes
Get-WmiObject -Query "SELECT * FROM Win32_Printer WHERE Default = $true"
In either case the filtering is done early to reduce the amount of data you are dealing with.
Remember – Filter early & format late
For more information on working with printers see chapter 10 of PowerShell and WMI – http://www.manning.com/powershellandwmi
May 5, 2012 12:50 PM
Posted by: Richard Siddaway
PowerShell,
WMI
A few times in the games you were asked for date time based information. Now WMI has a lot of classes that return WMI information. It is in an awkward format though
PS> Get-WmiObject -Class Win32_OperatingSystem | fl *time*
CurrentTimeZone : 60
LastBootUpTime : 20120505101515.296000+060
LocalDateTime : 20120505192615.170000+060
This translates as:
Year – four digits
Month – two digits
Day – two digits
Hour – two digits
Minute – two digits
Second – two digits
.
millionth of second but is usually constrained to milliseconds
+
minutes difference from GMT (UTC)
Its readable but only if you are used to it.
Ideally we want to convert this to a more reasonable looking date such as
05 May 2012 19:35:03
It is possible to take the WMI information, break it up into its components – its is returned as a string – and create a datetime object. Alternatively you can hunt through the .NET classes and find some date conversion methods.
That’s the hard way.
The easy way is to use the built in functionality on the WMI class!
If you put a WMI class through get-member you will discover a couple of Scriptmethods at the end of the data
PS> Get-WmiObject -Class Win32_OperatingSystem | Get-Member -MemberType ScriptMethod
TypeName: System.Management.ManagementObject#root\cimv2\Win32_OperatingSystem
Name MemberType Definition
—- ———- ———-
ConvertFromDateTime ScriptMethod System.Object ConvertFromDateTime();
ConvertToDateTime ScriptMethod System.Object ConvertToDateTime();
They are simple to use
If you need the rest of the data on the object
PS> $os = Get-WmiObject -Class Win32_OperatingSystem
PS> $os.ConvertToDateTime($os.LastBootUpTime)
05 May 2012 10:15:15
or if only want the last bootup time
PS> $os = [wmiclass]"\\.\root\cimv2:Win32_OperatingSystem"
PS> $os.ConvertToDateTime($(Get-WmiObject Win32_OperatingSystem | select -ExpandProperty LastBootUpTime))
05 May 2012 10:15:15
There are variations on these themes.
The conversion routines can be used in calculated fields in select and format cmdlets
See PowerShell and WMI chapters 3 and 4 for more details – http://www.manning.com/powershellandwmi
May 5, 2012 7:55 AM
Posted by: Richard Siddaway
PowerShellThe games are over for another year. The number of entries was huge – 150% increase over last year. Congratulations to the winners and to everyone who took part.
One thing I noticed was the number of scripts that made testing booleans harder than it needed to be.
A boolean can take one of two values – True or False. These are represented in PowerShell by $true and $false respectively
Lets create a couple of variables
PS> $x = $true
PS> $x
True
PS> $y = $false
PS> $y
False
A common test was:
PS> $a = $true
PS> $b = $false
PS> if ($a -eq $true){"Do something"}
Do something
or you might see
PS> if ($b -ne $true){"Do something else"}
Do something else
These work and are perfectly understandable.
They can be made simpler
PS> if ($a){"Do something"}
Do something
we get two ways of testing false using the –not operator and its alias of !
PS> if (-not $b){"Do something else"}
Do something else
PS> if (! $b){"Do something else"}
Do something else
Just as a final test to show this really works
PS> if ($b){"Do something"}else{"Do something else"}
Do something else
The thing to remember is that on an if statement or anywhere else where a condition is being tested it has to resolve to true or false. In this case the variable (or object property) already carries a boolean value so we can use it directly.
Its not a big saving but will mount up over time – keeps the scripts simpler and therefore keeps the errors down
April 29, 2012 6:01 AM
Posted by: Richard Siddaway
PowerShellAs April comes to close so does the extension for grading scripts in the recent games. I’ve been so busy grading haven’t had time to blog about the games. I’ll start to catch up on the backlog over the next few weeks. This years games have been huge with more than 150% growth in the number of scripts submitted. That is a lot of PowerShell.
The Deep Dive starts tonight – with keynotes tomorrow. This is shaping up to be the PowerShell event of the year.
Powershell and WMI will be available very soon.
Advanced Powershell – http://www.manning.com/jones2/ is well on the way and still on target for a release soon after Windows 8 and Powershell v3
Windows 8/windows 2012 release candidate will be with us in early June. Already had one user group session on the topic and there will be another one in May