Documente Academic
Documente Profesional
Documente Cultură
I can also do the same thing by using the Get-WmiObject cmdlet. This technique is shown here.
Get-wmiobject -list *thread*
So, I decide to query the WMI class. Here is the Windows PowerShell 2.0 version of the command.
Get-WmiObject win32_thread
I can do the same thing with the CIM cmdlets in Windows PowerShell 3.0. This command is shown here.
Get-CimInstance win32_thread
The command and the output from the command are shown here.
To understand the thread state, it is necessary to look up the ThreadState property. I can do this in the
MSDN article,Win32_Thread WMI class. The ThreadState values are shown here.
Value
Meaning
Running. It is executing.
Standby. It is about to run. Only one thread may be in this state at a time.
Transition. The thread is waiting for resources other than the processor.
The ThreadWaitReason value codes are shown in the table that follows.
Value
Meaning
Executive
FreePage
PageIn
PoolAllocation
ExecutionDelay
FreePage
PageIn
Executive
FreePage
PageIn
10
PoolAllocation
11
ExecutionDelay
12
FreePage
13
PageIn
14
EventPairHigh
15
EventPairLow
16
LPCReceive
17
LPCReply
18
VirtualMemory
19
PageOut
20
Unknown
BC, that is all there is to using Windows PowerShell and WMI to find information about threads. Join me
tomorrow when I will talk about more cool stuff.Therefore, the Notepad process is waiting and not ready for
the processor. The reason it is waiting is EventPairLow.
Name
InterfaceDescription
ifIndex Status
MacAddress
LinkSpeed
----
--------------------
------- ------
----------
---------
Ethernet 5
7 Disconnected 00-10-18-44-06-7A
0 bps
Ethernet 2
4 Disconnected 00-10-18-44-06-78
0 bps
Ethernet 4
6 Up
B8-AC-6F-82-68-DB
1 Gbps
Ethernet 3
5 Disconnected 00-1B-21-8E-EB-F5
0 bps
Ethernet
3 Disconnected 00-1B-21-8E-EB-F4
0 bps
If you are running in a Hyper-V environment, there is also a cmdlet to gather information for the VM NICs
on that host. A VM NIC is the equivalent of a network adapter for a VM.
PS C:\Users\Administrator> Get-VMNetworkAdapter -VMName DemoVM1
Name
IsManagementOs VMName
SwitchName MacAddress
Status IPAddresses
----
-------------- ------
---------- ----------
------ -----------
{192.168.0.3}
In the example above we choose a specific VM but you can also search for all VM NICs by specifying the
wildcard or * character after the cmdlet. An example of this cmdlet is given below.
PS C:\Users\Administrator> Get-VMNetworkAdapter *
Name
IsManagementOs VMName
SwitchName MacAddress
Status IPAddresses
----
-------------- ------
---------- ----------
------ -----------
{192.168.0.4}
{192.168.0.3}
Get-NetIPAddress will return the IP addresses that are configured on that system system for both IPv6
and IPv4. This can be run inside a VM or on the host.
PS C:\> Get-NetIPAddress
IPAddress
: fe80::bf7f%7
InterfaceIndex
: 7
InterfaceAlias
: Ethernet 5
AddressFamily
: IPv6
Type
: Unicast
PrefixLength
: 64
PrefixOrigin
: WellKnown
SuffixOrigin
: Link
AddressState
: Deprecated
ValidLifetime
: Infinite ([TimeSpan]::MaxValue)
: False
PolicyStore
: ActiveStore
IPAddress
: 192.168.191.127
InterfaceIndex
: 7
InterfaceAlias
: Ethernet 5
AddressFamily
: IPv4
Type
: Unicast
PrefixLength
: 16
PrefixOrigin
: WellKnown
SuffixOrigin
: Link
AddressState
: Tentative
ValidLifetime
: Infinite ([TimeSpan]::MaxValue)
: False
PolicyStore
: ActiveStore
InterfaceAlias
: Ethernet 4
InterfaceIndex
: 6
: ntdev.corp.microsoft.com
IPv6Address
: 2001:4898:1a:3:f0d3:dc16:89c6:86eb
IPv4Address
: 192.31.25.52
IPv6DefaultGateway
: fe80::8a75:56ff:fe3d:7380
IPv4DefaultGateway
: 192.31.25.1
DNSServer
: 158.55.16.178
You can use the Detailed flag with GIP to show more information.
PS C:\> GIP -Detailed
ComputerName
: GS-BDESKTOP
InterfaceAlias
: Ethernet 4
InterfaceIndex
: 6
InterfaceDescription
NetAdapter.LinkLayerAddress : B8-AC-6F-82-68-DB
NetAdapter.Status
: Up
NetProfile.Name
: work.microsoft.com
NetProfile.NetworkCategory
: DomainAuthenticated
NetProfile.IPv6Connectivity : Internet
NetProfile.IPv4Connectivity : Internet
IPv6Address
: 2001::86eb
IPv6TemporaryAddress
: 2001::e7b4
IPv6LinkLocalAddress
: fe80::86eb%6
IPv4Address
: 192.31.25.52
IPv6DefaultGateway
: fe80::8a75:56ff:fe3d:7380
IPv4DefaultGateway
: 192.31.25.1
NetIPv6Interface.NlMTU
: 1500
NetIPv4Interface.NlMTU
: 1500
NetIPv6Interface.DHCP
: Enabled
NetIPv4Interface.DHCP
: Enabled
DNSServer
: 158.55.16.178
Like most PowerShell cmdlets, Get-NetIPConfiguration returns rich scriptable objects. For example, the
default route is accessible directly.
PS C:\WINDOWS\system32> $Object = GIP 'Ethernet 4'
PS C:\WINDOWS\system32> $Object.IPv4DefaultGateway
ifIndex DestinationPrefix
NextHop
RouteMetric PolicyStore
------- -----------------
-------
----------- -----------
172.31.232.1
0.0.0.0/0
0 ActiveStore
Testing Connectivity
Windows Server 2012 R2 supports a new cmdlet for testing ICMP and TCP connectivity, called TestNetConnection (TNC).
ComputerName
: www.xbox.com
RemoteAddress
: 2600:1409::1ac
InterfaceAlias
: Ethernet 4
SourceAddress
: 2001::e7b4
PingSucceeded
: True
PingReplyDetails (RTT) : 2 ms
The output object of TNC includes the relevant WMIv2 objects of the local machine. This means you can
script against them directly. Below is an example of using TNC to rename the network adapter that is used
by default to reach www.xbox.com.
PS C:\WINDOWS\system32> tnc www.xbox.com | Rename-NetAdapter -NewName "ConnectsToXbox"
PS C:\WINDOWS\system32> $Object.NetAdapter
Name
InterfaceDescription
ifIndex Status
MacAddress
LinkSpeed
----
--------------------
------- ------
----------
---------
ConnectsToXbox
6 Up
B8-AC-6F-82-68-DB
Using the TraceRoute flag will return the list of hosts on the path to the specified target.
PS C:\WINDOWS\system32> tnc www.xbox.com -TraceRoute
ComputerName
: www.xbox.com
RemoteAddress
: 2600:1409:a:18f::1ac
1 Gbps
InterfaceAlias
: ConnectsToXbox
SourceAddress
: 2001::e7b4
PingSucceeded
: True
PingReplyDetails (RTT) : 2 ms
TraceRoute
: 20013::1
2001::2
2001::6c:1
TimedOut
2001:4898:8000:2:ff::36
TimedOut
TimedOut
TimedOut
TimedOut
2600:1409:a:18f::1ac
ComputerName
: www.bing.com
RemoteAddress
: 204.79.197.200
RemotePort
: 80
InterfaceAlias
: ConnectsToXbox
SourceAddress
: 192.31.25.5
PingSucceeded
: True
PingReplyDetails (RTT) : 0 ms
TcpTestSucceeded
: True
ComputerName
: HomeBase
RemoteAddress
: 192.168.0.5
RemotePort
InterfaceAlias
: ConnectsToXbox
SourceAddress
: 192.31.25.5
PingSucceeded
: True
PingReplyDetails (RTT) : 0 ms
TcpTestSucceeded
: False
ComputerName
: HomeBase
RemoteAddress
: 10.195.58.228
RemotePort
: 3389
AllNameResolutionResults : 10.195.58.228
MatchingIPsecRules
: Msit-Ipsec-Win8/WS8-Domain-CorpnetIpv4-Authip
NetworkIsolationContext
: Private Network
InterfaceAlias
: ConnectsToXbox
SourceAddress
: 192.31.25.5
NetRoute (NextHop)
: 192.31.25.1
PingSucceeded
: True
PingReplyDetails (RTT)
: 0 ms
TcpTestSucceeded
: False
The MatchingIPSecRules field tells us which IPsec rules are attempting to secure the connection, in this
case the IPsec rules that Microsofts IT department has deployed for DirectAccess. Because this is
PowerShell, the property in fact is a rich WMI object.
The NetworkIsolationContext field tells us which capability Windows store apps need to use to access the
resource. In order for Windows store apps to access HomeBase, they need to declare the Private Network
capability.
If youre wondering why DirectAccess isnt working, its because I havent provided my smartcard
credentials to the system.
PS C:\WINDOWS\system32> Get-DAConnectionStatus
Status : ActionableError
Substatus : StrongAuthorizationCredentialsNeeded
ComputerName
: www.xbox.com
RemoteAddress
: 2600:1409:a:181::1ac
RemotePort
: 80
InterfaceAlias
: ConnectsToXbox
SourceAddress
: 2001::e7b4
PingSucceeded
: True
PingReplyDetails (RTT) : 2 ms
TcpTestSucceeded
: True
Testing VM Connectivity
Windows Server 2012 R2 also helps with diagnosing connectivity issues when access to VMs is not
available like in service provider environments. In service provider environments, it will be common to see
tenant overlays on the physical network using Hyper-V Network Virtualization (HNV). With HNV, customers
can easily move their subnets to the cloud while preserving their existing IP addresses (called a Customer
Address or CA), and topology into the cloud so that existing services continue to work unaware of the
underlying fabrics address space (called a, Provider Address or PA), used by the service provider. As a
result of this isolation and indirection, testing connectivity between VMs is challenging and tools like TNC
may not always suffice.
Diagnosing connectivity for the service provider and tenant networks, however, remains important in order
to validate infrastructure setup or deployment configuration. To help diagnose these issues Windows
Server 2012 R2 introduces two new tools: PA Ping and Test-VMNetworkAdapter.
Test-VMNetworkAdapter
Test-VMNetworkAdapter allows admins to diagnose connectivity issues in the tenant network. The
challenge here is that admins may not have direct access to the VMs and therefore cannot run tools like
TNC from within the VM. Test-VMNetworkAdapter injects ICMP packets on the port that the VM is attached
to and awaits an echo response from the receiver VM:
PS C:\> Test-VMNetworkAdapter VMName Helen sender SenderIPAddress 10.20.20.5 ReceiverIPAddress
10.20.20.6 NextHopMacAddress f4-ce-46-2d-98-16 VMNetworkAdapterName HelenNic RoundTripTime :
16 milliseconds
If this command succeeds, this can indicate that the problem is in the VM, and not in the tenant network.
If the NextHopMacAddress is not known, use Select-NetVirtualizationNextHop cmdlet to look up several
parameters like NextHopMACAddress from the HNV database:
PS C:\> Select-NetVirtualizationNextHop DestinationCustomerAddress 10.20.20.6
SourceCustomerAddress 10.20.20.5 SourceVirtualSubnetID 5001
SourceCustomerAddress
: 10.20.20.5
DestinationCustomerAddress
: 10.20.20.6
SourceVirtualSubnetID
: 5001
NextHopAddress
: 0.0.0.0
SourceMACAddress
: fece462d9814
NextHopMACAddress
: fece462d9816
For business reasons you may want to avoid sending ICMP ping packets to their tenant VMs. To do so, use
the receiver parameter to enable an ICMP responder running on the switch port of the VM:
PS C:\> Test-VMNetworkAdapter VMName Helen receiver SenderIPAddress 10.20.20.5
ReceiverIPAddress 10.20.20.6 VMNetworkAdapterName HelenNic
The control channel inspects all packets and echoes back ICMP packets that contain the sequence number
100 in their payload. This number can be configured using the SequenceNumber parameter. Be sure to
use the same sequence number on both VMs so that the receiver may intercept and echo back the correct
ICMP packets.
Putting It Together
Lets take a look at an example scenario that merges the use of these cmdlets: Brian has just deployed
HNV on his network. His topology consists of multiple hosts with multiple VMs on each host. He wants to
validate connectivity between each VM and ensure HNV is deployed correctly.
First, he will use PA Ping (ping p) to validate connectivity over the physical infrastructure between each
VM. Then he will use Test-VMNetworkAdapter with sender and receiver parameters to validate
connectivity between each VM. In doing so he will validate that the indirection introduced by HNV has
resulted in the mapping as configured at the time of deployment. Finally, he can use the same script with
Test-VMNetworkAdapter without the receiver parameter to validate correct firewall configuration in the
operating system on the VMs.
By doing this, Brian can validate the correct configuration of HNV on his network and ensure connectivity
between all VMs. If a customer were to report a connectivity problem, Brian can quickly resolve it back to
the customer saying that he expects the problem is in the customer VM! The customer can now use TNC to
detect further problems.
Discovering Shares
Windows 8 and Windows Server 2012 ship with PowerShell 3.0 and a suite of extra modules. Many of these
modules are created by using the cmdlets-over-objects technology, which means that you take a WMI
class, wrap it in XML, and you get a PowerShell module. Details of how to create your own CDXML modules
are provided in my book, PowerShell and WMI.
You can easily tell if your module has been constructed in this manner because it will have a .cdxml
extension. In many instances, the WMI classes that are used for this process are new to Windows 8 and
Windows Server 2012, and they are not available on earlier versions of Windowseven if you install
Windows PowerShell 3.0.
The cmdlets are in a module called SmbShare. If you use Get-SmbShare, you see this output on a
Windows 8-based computer:
> Get-SmbShare | Format-Table -AutoSize
Description
C$
C:\
Default share
D$
D:\
Default share
IPC$ *
Remote IPC
Users *
C:\Users
This is for the local machine, but more importantly, you need to be able to administer your remote servers.
Lets look at the parameters that are available with Get-SmbShare:
> Get-Command Get-SmbShare -Syntax
Get-SmbShare [[-Name] <string[]>] [[-ScopeName] <string[]>] [-Scoped <bool[]>] [-Special <bool[]>]
[-ContinuouslyAvailable <bool[]>] [-ShareState <ShareState[]>] [-FolderEnumerationMode
<FolderEnumerationMode[]>] [-CachingMode <CachingMode[]>] [-ConcurrentUserLimit <uint32[]>] [AvailabilityType <AvailabilityType[]>] [-CaTimeout<uint32[]>] [-EncryptData <bool[]>] [-IncludeHidden] [CimSession <CimSession[]>] [-ThrottleLimit <int>] [-AsJob][<CommonParameters>]
You will notice one glaring omission. There isnt a ComputerName parameter. One of the quirks of
CDXML-based modules is that you need to use CIM sessions to access remote machines (or run the
command over a Windows PowerShell remoting session).
$sess = New-CimSession -ComputerName Win12R2
Get-SmbShare -CimSession $sess
$sess | Remove-CimSession
You will automatically get PSComputerName output as an additional property. If you try to run this
against an earlier version of Windows with Windows PowerShell 2.0, it will fail because you need
WSMAN 3.0 on the remote system to use CIM sessions.
The older versions of Windows cant be left out of this, so you need to look at another way of retrieving the
data. WMI supplies a Win32_Share class that you can use:
> Get-WmiObject -Class Win32_Share | Format-Table -AutoSize
Name Path
---- ----
Description
-----------
C:\
Default share
D$
D:\
Default share
IPC$
Remote IPC
Users C:\Users
The next step is to extend this to a remote machine. Get-WmiObject has had a
ComputerName parameter since PowerShell 1.0. Back in those days, it was our only tool for working
remotely!
> Get-WmiObject -Class Win32_Share -ComputerName Win12R2 | Format-Table AutoSize
So, you get to the age-old question, Which do I use?
The drawback with CIM sessions is that you need WSMAN 3.0 on the remote machine, which means that
PowerShell 3.0 or above must be installed. On older machines with Windows PowerShell 2.0, you need to
have WMI allowed through any firewalls you have between you and the remote machine. As the
percentage of machines with WSMAN 3.0 increases, you need to be maximizing the use of CIM sessions.
The answer is to test the version of WSMAN that you have installed and proceed accordingly:
> Test-WSMan -Authentication default -ComputerName win12r2
wsmid
: http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd
ProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
ProductVendor : Microsoft Corporation
ProductVersion : OS: 6.3.9600 SP: 0.0 Stack: 3.0
The value you need to test is the Stack property on the ProductVersion. This leads you to a function like
this:
function get-share {
[CmdletBinding()]
param(
[parameter(Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[string[]]$computername
)
PROCESS{
foreach ($computer in $computername){
$stack = ((Test-WSMan -Authentication default -ComputerName $computer -ErrorAction
SilentlyContinue ).ProductVersion -split ": ")[-1]
switch ($stack) {
"2.0" {
Get-WmiObject -Class Win32_Share -ComputerName $computer |
select PSComputername, Name, Path, Description
}
"3.0" {
$sess = New-CimSession -ComputerName Win12R2
Get-SmbShare -CimSession $sess |
select PSComputername, Name, Path, Description
$sess | Remove-CimSession
}
default {Write-Warning -Message "Couldn't determine WSMAN Stack version for $computer" }
} # end switch
} # end foreach
} # End process
}
Take a pipeline input, and test the WSMAN version for a computer that is passed in. This line may look a bit
intimidating:
((Test-WSMan -Authentication default -ComputerName $computer -ErrorAction
SilentlyContinue ).ProductVersion -split ": ")[-1]
Its not that bad when you break it down...
This gets the information:
Test-WSMan -Authentication default -ComputerName $computer -ErrorAction SilentlyContinue
This simply takes the ProductVersion property:
(Test-WSMan -Authentication default -ComputerName $computer -ErrorAction
SilentlyContinue ).ProductVersion
This splits that property on a : :
-split ": "
The result is an array of which you take the last element by using the -1 index. Try building up the
command like this at the Windows PowerShell prompt to see how it all works.
A switch statement is used to determine actions based on the WSMAN stack version. Version 2.0 uses WMI
and version 3.0 uses CIM. The appropriate cmdlet is run and then a select statement is used to determine
the data returned. In this case, the PSComputerName property is used to identify the machine from
which we generate the data.
If the stack version isnt 2.0 or 3.0, the switch statement drops into the default option, which prints a
warning on screen.
What about the situation where you have hundreds or thousands of machines? Do you want to wait for this
to run?
If the answer is, No, you could try turning this into a workflow, but the switch statement doesnt work
very well in workflows. We recommended against using it in PowerShell in Depth. Your choices are to
completely rewrite or to use Windows PowerShell jobs. Get-WmiObject and Get-SmbShare have an
AsJob parameter.
A Windows PowerShell job will create a job object to perform your processing and then immediately
continue with the next line in the script. This works for Get-WmiObject, but there is an issue using GetSmbShare like this because the next line will immediately remove the CIM session the job is trying to use,
and the job will fail.
The answer is to use Wait-Job to test the completion of the job, which will delay the whole script and
negate the reason for using jobs, or to move the whole process into a script block and use Start-Job.
function get-share {
[CmdletBinding()]
param(
[parameter(Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[string[]]$computername
)
PROCESS{
foreach ($computer in $computername){
$stack = ((Test-WSMan -Authentication default -ComputerName $computer -ErrorAction
SilentlyContinue).ProductVersion -split ": ")[-1]
switch ($stack) {
"2.0" {
Get-WmiObject -Class Win32_Share -ComputerName $computer -AsJob
}
"3.0" {
$sb = {
param($comp)
$sess = New-CimSession -ComputerName $comp
Get-SmbShare -CimSession $sess
$sess | Remove-CimSession
}
Incorporate it into the server documentation tool that you read about in the first article in this
series: The Admins First Steps: Documenting Servers.
After that, you use the ContextType class to say that you are looking at the local machine rather than the
domain. TheSystem.DirectoryServices.AccountManagement classes arent used much, which is a
shame because they are powerful and they span local and domain level activities.
You can then use the context type and the local machine name to create a context.
The IdentityType defines what you are using to identify objectsin this case, the SamAccountName.
Now you can use all of that data in the FindByIdentity() method of the GroupPrincipal class to find the
group. TheMembers property holds the members as you might expect; but the final piece is that you have
to dig into the Context of the member to discover whether the object comes from the domain or from the
local machine.
Luckily the code runs much faster than I can write about it and you get results like this:
Domain
SamAccountName
------
--------------
WIN12R2
Administrator
PROCESS{
foreach ($computer in $computername) {
$context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext
-ArgumentList $ctype, $computer
$idtype = [System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName
$group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($context,
$idtype, 'Administrators')
$group.Members |
select @{N='Server'; E={$computer}}, @{N='Domain'; E={$_.Context.Name}}, samaccountName
} # end foreach
} # end PROCESS
}
Win12R2", "W12SUS" | get-localgroupmember
Start by defining the function and parameter. In this case, youre only interested in the remote computer
name. When you use an array as the type, you can also do this:
get-localgroupmember -computername Win12R2, w12sus
but only if you have the Foreach loop in the PROCESS block. (You dont have to capitalize these blocks
of codeI do it to make my code more readable.)
You only need to load the .NET Framework classes, define the context, and identity types once. So those
steps go into the BEGIN block, which executes once when the first object in the pipeline hits the function.
The PROCESS block loops through the computers and creates a context for each machine. The
Administrators group is found and the membership list is extracted. You are working against remote
machines so the computer is added to the output to identify to which machine the results apply.
You can use this function on the pipeline as shown or interactively by passing one or more computer
names to the function.
Save the results for comparison against a future examination to track changes.
AK, thats how you use Windows PowerShell to check the membership of your local groups. Next time Ill
have another idea for you to try as you bring more automation into your environment.