May 23 2012 12:46PM GMT
Posted by: Richard Siddaway
PowerShell 3,
WMI
I found a class new to me - Msft_Providers and this got me interested in WMI providers.
PS> Get-CimInstance -Class Msft_Providers | select -ExpandProperty provider
Msft_ProviderSubSystem
SCM Event Provider
WmiPerfClass
That seems a bit low. Digging a bit more I got back to the old favourite __provider.
Get-CimInstance -Class __provider | Measure-Object
produces an answer of 43 – not quite the answer to life, the universe and everything but close.
Is there any overlap between the two groups of providers?
$providers = Get-CimInstance -Class Msft_Providers | select -ExpandProperty provider
Get-CimInstance -Class __provider | where Name -in $providers | select Name
provides the answer
Msft_ProviderSubSystem
SCM Event Provider
In case you were wondering – “Starting with Windows Vista, the WMIPerfClass Provider and the WMIPerfInst Provider dynamically provide performance counter data for the WMI Performance Counter Classes.”
see http://msdn.microsoft.com/en-us/library/windows/desktop/aa392740(v=vs.85).aspx
One interesting property is the Hosting Model
Get-CimInstance -Class __provider | select HostingModel -Unique
Decoupled:NonCOM
NetworkServiceHost
WmiCore
LocalSystemHost
LocalServiceHost
NetworkServiceHost:[ReliabilityMetricsProvider]
But what do these mean
Full explanations for these and the other hosting models can be found at
http://msdn.microsoft.com/en-us/library/aa392509(VS.85).aspx
WmiCore - Activate provider in host to the WMI service. This hosting model is only supported for operating system components.
WmiCoreOrSelfHost - Activate provider in host to the WMI service or as local server. This hosting model is only supported for operating system components.
SelfHost - Activate provider as a local server implementation.
Decoupled:Com - Activate provider as a decoupled COM provider. See http://msdn.microsoft.com/en-us/library/aa390882(v=vs.85).aspx
Decoupled:NonCom - Activate provider as a non-COM event provider.
LocalSystemHost - Activate provider in the provider host process that is running under the LocalSystem account.
LocalSystemHostOrSelfHost - The provider is self-hosted or loaded into the Wmiprvse.exe process running under the LocalSystem account.
NetworkServiceHost - Activate provider in the provider host process that is running under the NetworkService account.
LocalServiceHost - Activate provider in the provider host process that is running under the LocalService account.
NetworkServiceHostOrSelfHost - The provider is self-hosted or loaded into the WmiPrvse.exe process running under the NetworkService account. NetworkServiceHostOrSelfHost is the default configuration when the HostingModel property in __Win32Provider is NULL. Because NetworkServiceHostOrSelfHost is the default, providers from earlier operating systems can continue to work in Windows Vista, Windows Server 2008, and later operating systems.
Get-CIMInstance is a new cmdlet in PowerShell v3. It is part of the new API for working with WMI. I will be blogging about these in greater detail over the next weeks and months as Powershell v3 is released.
More information on providers and the CIM cmdlets can be found in PowerShell and WMI – www.manning.com/powershellandwmi
May 21 2012 1:56PM GMT
Posted by: Richard Siddaway
PowerShell,
User Group
29 May 2012
PowerShell and Windows server 2012 – new functionality pt 2
http://msmvps.com/blogs/richardsiddaway/archive/2012/05/08/uk-powershell-group-may-2012.aspx
4 July
Jonathan Medd
XenDesktop and PowerShell
This will be at the slightly later time of 8.30 BST. Details to follow
May 20 2012 12:40PM GMT
Posted by: Richard Siddaway
Network,
PowerShell v2,
PowerShell 3,
WMI
In the last post I showed that there was an issue with the way the SetDNSServerSearchOrder of the Win32_NetworkAdapterConfiguration class worked
This would work
$nic = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "Index=7"
$nic.SetDNSServerSearchOrder("10.10.54.201")
but using Invoke-WmiMethod failed
After discussions with Bartek Bielawski (PowerShell MVP) and a bit more digging I found that for multiple DNS servers this would work
$dnsserver = "10.10.54.201", "10.10.54.98"
Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "Index=7" | Invoke-WmiMethod -Name SetDNSServerSearchOrder -ArgumentList (, $dnsserver)
Its necessary to create an array as the input argument (, $variable) – its a unary array ie one element array
if you want to use just a single DNS server then you need to use the unary array trick twice – once when you create the variable and again when you use Invoke-wmimethod. Messy but it works
$dnsserver = (,"10.10.54.201")
Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "Index=7" | Invoke-WmiMethod -Name SetDNSServerSearchOrder -ArgumentList (, $dnsserver)
If you want to use the new CIM cmdlets in PowerShell v3 – its easy if you have multiple DNS servers
$dnsserver = "10.10.54.201", "10.10.54.98"
Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "Index=7" | Invoke-CimMethod -MethodName SetDNSServerSearchOrder -Arguments @{DNSServerSearchOrder = $dnsserver}
for a single one we just need to create a unary array on the Arguments parameter
$dnsserver = "10.10.54.201"
Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "Index=7" | Invoke-CimMethod -MethodName SetDNSServerSearchOrder -Arguments @{DNSServerSearchOrder = (,$dnsserver)}
This is not satisfactory because we have to adopt different techniques depending on the number of DNS servers we need to put into NIC property. This is NOT a PowerShell issue – it has to be a WMI issue because the IP address that we saw last time also takes an array and it was very happy with a single value.
Hopefully this is not something that will come up too often but be aware of these options when working with WMI methods
May 20 2012 4:34AM GMT
Posted by: Richard Siddaway
Network,
PowerShell,
WMI
At some stage we may need to reset our NIC back to having a static address
$index = 7
$nic = Get-WmiObject -Class Win32_NetworkAdapterConfiguration `
-Filter "Index=$index"
$ipaddress = @("10.10.54.202")
$subnet = @("255.255.255.0")
Invoke-WmiMethod -InputObject $nic -Name EnableStatic -ArgumentList $ipaddress, $subnet
$dnsserver = "10.10.54.201"
$nic.SetDNSServerSearchOrder($dnsserver)
#Invoke-WmiMethod -InputObject $nic -Name SetDNSServerSearchOrder -ArgumentList $dnsserver
We get the configuration of the NIC and use the EnableStatic method to set the address and subnet
The SetDNSServerSearchOrder method is used to set the DNS server.
Notice I haven’t been able to use Invoke-WmiMethod at this point – I’ve had to call the method directly on the object. There appears to be an issue with the formatting of the DNS server addresses as Invoke-WmiMethod complains that the argument has to be an array.
This is under investigation.
More on using WMI with PowerShell can be found in PowerShell and WMI. Chapter 11 covers network adapters in detail. More details from www.manning.com/powershellandwmi
May 18 2012 2:00PM GMT
Posted by: Richard Siddaway
We have seen how to set the NIC to use DHCP to get its address. This post shows how to set the alternative configuration on the NIC. If you just want APIPA then do nothing – other wise use this script
$HKLM = 2147483650 #HKEY_LOCAL_MACHINE
$index = 7
$nic = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "Index=$index"
$key = "SYSTEM\CurrentControlSet\services\Tcpip\Parameters\Interfaces\$($nic.SettingID)"
Invoke-WmiMethod -Class StdRegprov -Name SetDWORDvalue -ArgumentList $hklm, $key, "AddressType", 2
Invoke-WmiMethod -Class StdRegprov -Name SetMULTISTRINGvalue -ArgumentList $hklm, $key, "Alternate_$($nic.SettingID)", "ActiveConfigurations"
Invoke-WmiMethod -Class StdRegprov -Name SetSTRINGvalue -ArgumentList $hklm, $key, "10.10.54.202", "DhcpIpAddress"
Invoke-WmiMethod -Class StdRegprov -Name SetSTRINGvalue -ArgumentList $hklm, $key, "10.10.54.201", "DhcpNameServer"
Invoke-WmiMethod -Class StdRegprov -Name SetSTRINGvalue -ArgumentList $hklm, $key, "255.255.255.0", "DhcpSubnetMask"
Again I’m cheating by defining the NIC in terms of its Index number
The registry key is derived from the SettingID property of the NIC
We then need to set a number of registry values. The AddressType sets the alternative configuration to use our informations rather than APIPA. The ActiveCinfigurations value is set using the SettingID property of the NIC
The address, subnetmask, and names server are set.
If you look carefully at the lines where we use the SetMULTISTRINGvalue and SetSTRINGvalue methods you will notice that we give the hive, key, value and then registry value name whereas the SetDWORDvalue method we give hive, key, value name and then value.
This is a quirk of Invoke-WmiMethod
The WMI documentation for SetMULTISTRINGvalue and SetSTRINGvalue methods state the parameters should be:
- hive
- registry key
- registry value name
- value
This order is constant across the Set* methods of the StdRegProv class - see http://msdn.microsoft.com/en-us/library/windows/desktop/aa393600(v=vs.85).aspx
If we do some investigation
PS> ([wmiclass]"StdRegprov").GetMethodParameters(’SetSTRINGvalue’)
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 4
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
hDefKey : 2147483650
sSubKeyName :
sValue : hello
sValueName :
This clearly shows we need to give the value before the value name.
the same holds true if we investigate using Get-CimClass in PowerShell v3
Get-CimClass -ClassName StdRegProv |
select -ExpandProperty CimClassMethods |
where Name -eq "SetStringValue" |
select -ExpandProperty Parameters
produces
Name CimType Qualifiers
—- ——- ———-
hDefKey UInt32 {ID, IN}
sSubKeyName String {ID, IN}
sValue String {ID, in}
sValueName String {ID, in}
if we use Invoke-CimMethod its not to much of a problem as we have to provide the value name and value pairs as a hash table we are not relying on argument order.
I’ll post an alternative listing using the CIM cmdlets another time
May 18 2012 12:07PM GMT
Posted by: Richard Siddaway
Books,
PowerShell 3
Three new chapters are added to the MEAP – Manning Early Access Program
Chapter 3 – Using the PowerShell help system – includes PowerShell v3 Updateable help
Chapter 5 – Working with PSsnapins and Modules
Chapter 9 – Formatting
www.manning.com/powershellindepth
May 17 2012 1:04PM GMT
Posted by: Richard Siddaway
An if statement is used to test a condition and if is true do one thing and do another if it is false. It can be written generically as
if (<condition>){ do stuff}
else {do other stuff}
Sometimes we need to test numerous alternatives. We could use multiple if statements, sometimes we have to nest them which can lead to code like this
Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType=3" |
foreach {
if ($_.FreeSpace -gt 1tb){Write-Host "Over 1TB of disk space free"}
else {
if ($_.FreeSpace -ge 500gb){Write-Host "Over 500GB of disk space free"}
else {
if ($_.FreeSpace -ge 300gb){Write-Host "Over 300GB of disk space free"}
else {
if ($_.FreeSpace -ge 200gb){Write-Host "Over 300GB of disk space free"}
else {
if ($_.FreeSpace -ge 100gb){Write-Host "Over 100GB of disk space free"}
else {
Write-Host "Insufficient disk space"
}
}
}
}
}
}
That’s not fun to write and its even less fun to debug or change
The code can be simplified by using if – elseif – else
Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType=3" |
foreach {
if ($_.FreeSpace -gt 1tb){Write-Host "Over 1TB of disk space free"}
elseif ($_.FreeSpace -ge 500gb){Write-Host "Over 500GB of disk space free"}
elseif ($_.FreeSpace -ge 300gb){Write-Host "Over 300GB of disk space free"}
elseif ($_.FreeSpace -ge 200gb){Write-Host "Over 300GB of disk space free"}
elseif ($_.FreeSpace -ge 100gb){Write-Host "Over 100GB of disk space free"}
else{Write-Host "Insufficient disk space"}
}
This much more compact and understandable. We can do a better job if we use a switch statement which is similar in concept to if-elseif-else
Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType=3" |
foreach {
switch ($_.FreeSpace) {
{$_ -gt 1tb} {Write-Host "Over 1TB of disk space free"; break}
{$_ -ge 500gb} {Write-Host "Over 500GB of disk space free"; break}
{$_ -ge 300gb} {Write-Host "Over 300GB of disk space free"; break}
{$_ -ge 200gb} {Write-Host "Over 300GB of disk space free"; break}
{$_ -ge 100gb} {Write-Host "Over 100GB of disk space free"; break}
default {Write-Host "Insufficient disk space"}
}
}
We select the object to test and use $_ as a placeholder. Each line in the switch statement is a single test. The default statement is for anything that doesn’t pass any of the preceding tests
One difference between the if statements and switch is that with the if statements as soon as a condition is true testing stops. With switch testing would continue through all tests – break is used to stop that
When you need to perform multiple tests consider using a switch statement – it is less typing and easier to debug
May 16 2012 3:12PM GMT
Posted by: Richard Siddaway
PowerShell,
Network,
WMI
The next step on our journey to an alternative configuration is setting the NIC to use DHCP
I will keep cheating for now and specify the NIC – on my machine I now it is the NIC whose Win32_NetworkAdapterConfiguration has an Index of 7
$index = 7
Get-WmiObject -Class Win32_NetworkAdapterConfiguration `
-Filter "Index=$index" |
Invoke-WmiMethod -Name EnableDHCP
This sets the IP address to be obtained automatically via DHCP BUT it doesn’t set the DNS server to be delivered via DHCP. The old static DNS entries are retained.
To resolve this we use the SetDNSServerSearchOrder method without any arguments
$index = 7
$nic = Get-WmiObject -Class Win32_NetworkAdapterConfiguration `
-Filter "Index=$index"
Invoke-WmiMethod -InputObject $nic -Name EnableDHCP
Invoke-WmiMethod -InputObject $nic -Name SetDNSServerSearchOrder
I’ve modified the script slightly so we create an object for the WMI class and then use that object as the InputObject on two calls to Invoke-WmiMethod
We could have just as easily used
$nic.EnableDHCP()
$nic.SetDNSServerSearchOrder()
Now that we have the NIC set to use DHCP we need to configure the Alternative Configuration
More information on working with network adapters can be found in PowerShell and WMI – www.manning.com/powershellandwmi
May 16 2012 1:50PM GMT
Posted by: Richard Siddaway
I often saw scripts that did something like this
function test1 {
param (
[string]$computername
)
if (!$computername){
$computername = $env:COMPUTERNAME
}
Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computername
}
A function, or script, defines a parameter. The first thing the function does it test the value of the parameter and if it doesn’t exist it sets it to a default value.
No, no, no – you are making work for yourself.
Get PowerShell to do the work for you
function test2 {
param (
[string]$computername = $env:COMPUTERNAME
)
Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computername
}
See the difference?
The parameter definition now contains a default value. If you don’t specify the parameter and a value the default kicks in and the function works.
Cuts down typing and gets PowerShell to do the work.