PowerShell for Windows Admins


August 20, 2011  12:29 PM

Powershell and WMI–MEAP Chapters 12 and 13

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Chapters 12 and 13 have been added to the early access program.

 

Chapter 12: Internet Information Server (IIS) may not be the first application that comes to mind when we think of using WMI to administer remote servers, but it provides a lot of functionality. You’ll learn to administer the web server itself, websites, applications, and application pools.

Chapter 13: Configuring a new server is a task that occurs on a regular basis in most organizations. All of the activities required to configure a new server take time. You can use PowerShell functions to perform these tasks remotely so you don’t need to spend time accessing the server directly.

The code for all chapters is available for download.

 

The MEAP is available from http://www.manning.com/siddaway2/

August 19, 2011  1:10 PM

Testing MAC address changes

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

My recent post on using MSNdis_EthernetCurrentAddress to get the MAC address may have had you saying so what because I can do this

 

Get-WmiObject -Class Win32_NetworkAdapter -ComputerName "." | select Name, MACAddress

 

However, there is another class MSNdis_EthernetPermanentAddress which shows the permanent address. This means we can see if the MAC address has been changed. This does happen in a few places including NLB.

function convert-macaddresstostring{            
 param ($address)            
             
 $values = @()            
 $address |             
 select -ExpandProperty Address |            
 foreach {            
  $values += ([convert]::ToString($_,16)).ToUpper().PadLeft(2,"0")            
 }            
             
 $values -join "-"            
}             
            
function test-macaddresschange {            
param(            
 [string]$computer="."            
)            
Get-WmiObject -Namespace root\wmi -Class MSNdis_EthernetCurrentAddress `
-ComputerName $computer |            
foreach {            
              
  $currentmac = convert-macaddresstostring $($_.NdisCurrentAddress)            
              
  $perm = Get-WmiObject -Namespace root\wmi  `
  -Class MSNdis_EthernetPermanentAddress -ComputerName $computer `
  -Filter "InstanceName='$($_.InstanceName)'"            
              
  $permanentmac = convert-macaddresstostring $($perm.NdisPermanentAddress)            
              
  New-Object -TypeName PSobject -Property @{            
  Computer = $_.__SERVER            
  Adapter = $_.InstanceName            
  CurrentMACAddress = $currentmac            
  PermanentMACAddress = $permanentmac            
 }            
}            
}            
            

You should recognise this from the previous post. We use MSNdis_EthernetCurrentAddress  and loop through the adapters. Then MSNdis_EthernetPermanentAddress  is used to get the permanent MAC address of the instance. Instance name is used as a filter. The conversion of the MAC address from integer array to string is pushed into its own function.

The output object is altered to show current and permanent addresses


August 18, 2011  1:01 PM

Find the MAC address

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

One thing that has bugged me for years is having to use the /all parameter with ipconfig to get the MAC address. It also doesn’t work on remote machines. bah humbug.

The MSNdis_EthernetCurrentAddress class in the root\wmi namespace offers a quicker way

function get-macaddress {            
param(            
 [string]$computer="."            
)            
Get-WmiObject -Namespace root\wmi -Class MSNdis_EthernetCurrentAddress `
-ComputerName $computer |            
foreach {            
 $values = @()            
 $_.NdisCurrentAddress |             
 select -ExpandProperty Address |            
 foreach {            
  $values += ([convert]::ToString($_,16)).ToUpper().PadLeft(2,"0")            
 }            
             
 $mac = $values -join "-"            
 New-Object -TypeName PSobject -Property @{            
  Computer = $_.__SERVER            
  Adapter = $_.InstanceName            
  MACAddress = $mac            
 }            
}            
}

Get the WMI objects for MSNdis_EthernetCurrentAddress. For each of them take the NdisCurrentAddress and expand the address property. This gives 6 integer values one for each element of the MAC address. We convert them to hex, convert to upper case and pad a 0 to the left if needed. the MAC address is created by joining those 6 values with a hyphen.

An object is created to output the results


August 17, 2011  2:19 AM

Half price PowerShell books

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Check www.manning .com for a half price deal on PoweShell books:

  • PowerShell in Practice
  • PowerShell and WMI
  • PowerShell in Action
  • Learn PowerShell in a month of lunches

Hurry. Today only!


August 9, 2011  12:58 PM

Book review: SQL Server DMVs in Action

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Title: SQL Server DMVs in Action

Author: Ian Stirk

Publisher: Manning

ISBN: 978-1-935182-73-3

 

DMVs are Dynamic Management Views – they were introduced in SQL Server 2005 and further refined in SQL Server 2008. They maintain information about whats happening on on your SQL Server – in real time. They supply a snapshot of whats happening and a view of what has happened as they accumulate data since SQL Server was started.

DMVs are a very powerful, but little understood facet of SQL Server.  The book has 11 chapters:

  1. The DMV gold mine
  2. Common patterns
  3. Index DMVs
  4. Improving poor query performance
  5. Further query improvements
  6. Operating System DMVs
  7. Common Language RunTime DMvs
  8. Resolving Transaction issues
  9. Database level DMVs
  10. The self-healing database
  11. Useful scripts

At 325 pages its not a massive book but it is packed with useful information. The first two chapters supply an overview of DMVs and some common code patterns that will be re-used throughout the book. The second chapter will repay careful reading as the themes introduced here permeate the whole book.

The books second part – chapters 3-11 – cover how to use DMVs to solve database related problems. The chapter titles speak for themselves with chapter 3 showing ways to identify missing indexes and 4 and 5 showing how to identify and improve SQL queries

Chapter 6 covers SQL Server’s interaction with the OS and the server – showing how to identify waits and blocks. Chapter 7 on the CLR is of great interest if you are using CLR code in your queries. Chapters 8 and 9 on transactions and databases are back to finding SQL Server related issues.. The last two chapters show how to pull all of this together to produce a database that can start to heal its own problems – personally I’d prefer it to make suggestions rather than implement but that is just details. The final chapter presents some useful scripts that build on the earlier chapters.

The books 100+ code snippets are ready to use and directly useful in your environment

If you work with SQL Server this is one you should have on your book case.  Highly recommended


August 7, 2011  10:05 AM

MSDiskDriver_Performance

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

We have looked at the MSDiskDriver_Geometry  class now lets look at the MSDiskDriver_Performance class

This is a bit more complicated because the Perfdata property is actually an instance of the MSDiskDriver_PerformanceData class

function get-msdiskdriverperfomance  {            
[CmdletBinding()]            
param (            
 [string]$computer="."            
)            
            
PROCESS{            
$date = Get-Date -Format F            
Get-WmiObject -Namespace root\wmi -Class msdiskdriver_performance `
-ComputerName $computer |             
foreach {            
 $perfdata =  $_ | select InstanceName, Active, DeviceName             
 $perfdata |            
 Add-Member -MemberType NoteProperty -Name TimeStamp -Value $($date) -PassThru |            
 Add-Member -MemberType NoteProperty -Name BytesRead -Value $($_.PerfData.BytesRead) -PassThru |            
 Add-Member -MemberType NoteProperty -Name BytesWritten -Value $($_.PerfData.BytesWritten) -PassThru |            
 Add-Member -MemberType NoteProperty -Name IdleTime -Value $($_.PerfData.IdleTime) -PassThru |            
 Add-Member -MemberType NoteProperty -Name QueryTime -Value $($_.PerfData.QueryTime) -PassThru |            
 Add-Member -MemberType NoteProperty -Name QueueDepth -Value $($_.PerfData.QueueDepth) -PassThru |            
 Add-Member -MemberType NoteProperty -Name ReadCount -Value $($_.PerfData.ReadCount) -PassThru |            
 Add-Member -MemberType NoteProperty -Name ReadTime -Value $($_.PerfData.ReadTime) -PassThru |            
 Add-Member -MemberType NoteProperty -Name SplitCount -Value $($_.PerfData.SplitCount) -PassThru |            
 Add-Member -MemberType NoteProperty -Name StorageDeviceNumber -Value $($_.PerfData.StorageDeviceNumber) -PassThru |            
 Add-Member -MemberType NoteProperty -Name WriteCount -Value $($_.PerfData.WriteCount) -PassThru |                     
 Add-Member -MemberType NoteProperty -Name WriteTime -Value $($_.PerfData.WriteTime)             
            
$perfdata             
}            
}            
}

We get round that by creating an object using select and then using Add-member to add the performance properties.

I get three instances of the MSDiskDriver_Performance  class return which I think correspond to the physical disk and the two logical disks. I need to do a bit more investigation to confirm. In the mean time it does give some interesting statistics on our disks


August 7, 2011  9:26 AM

MSDiskDriver classes

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

The root\wmi namespace contains four MSDiskDriver related classes

gwmi -Namespace root\wmi -Class msdiskdriver* -List | select name

MSDiskDriver
MSDiskDriver_Performance
MSDiskDriver_PerformanceData
MSDiskDriver_Geometry

 

The first class – MSDiskDriver – is a super class that calls the other three. Documentation appears to be almost non-existent (there are references to an older copy of the WMI SDK but that doesn’t seem to be available. The MSDiskDriver_PerformanceData class is referenced from the

MSDiskDriver_Performance class as the Perfdata property. We will ignore the  MSDiskDriver class and start with the disk geometry

 

function get-msdiskdrivergeometry  {           
[CmdletBinding()]           
param (           
[string]$computer="."           
)           
BEGIN{           
Add-Type @"
public enum MediaType : int {
Unknown = 0,
RemovableDisk = 11,
HardDisk = 12
}
"@
           
}           
PROCESS{           
Get-WmiObject -Namespace root\wmi -Class msdiskdriver_geometry `
-ComputerName $computer | select InstanceName, Active,            
@{N="DiskType"; E={[mediatype]($($_.MediaType))}},           
Cylinders, TracksPerCylinder, SectorsPerTrack, BytesPerSector           
}           
}

Define an enumeration for the media types – values 1-10 and 13-22 related to floppy or similar devices

use Get-WmiObject to get the object and display – use the enum to decode the media type

On my machine this produces

InstanceName      : IDE\DiskST9250320AS_____________________________HP07____\5&b0fd174&0&1.0.0_0
Active            : True
DiskType          : HardDisk
Cylinders         : 30401
TracksPerCylinder : 255
SectorsPerTrack   : 63
BytesPerSector    : 512

 

compare with the results of Win32_DiskDrive

Get-WmiObject Win32_DiskDrive | select PNPDeviceID, Status, MediaType, TotalCylinders,
TracksPerCylinder, SectorsPerTrack, BytesPerSector

PNPDeviceID       : IDE\DISKST9250320AS_____________________________HP07____\5&B0FD174&0&1.0.0
Status            : OK
MediaType         : Fixed hard disk media
TotalCylinders    : 30401
TracksPerCylinder : 255
SectorsPerTrack   : 63
BytesPerSector    : 512


August 5, 2011  1:11 PM

Change Volume Label

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

While we are looking at disks I’ll add this function to the mix

function set-volumelabel {            
[CmdletBinding()]            
param (            
 [string]$computer=".",            
             
 [parameter(Mandatory=$true)]            
 [string]            
 [ValidatePattern("^[A-Z]{1}:{1}`$")]            
 $drive,            
             
 [parameter(Mandatory=$true)]            
 [string]$newname            
              
)            
            
Get-WmiObject -Class Win32_Volume -ComputerName $computer -Filter "DriveLetter='$drive'"  |            
Set-WmiInstance -Arguments @{Label=$newname}            
}

Its job is to set the volume label. Give it a drive and a new name as parameters. The same pair of Get-WmiObject and Set-WmiInstance work their magic again to make the change


August 5, 2011  11:58 AM

Setting the drive letter

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

I’ve been working on some WMI  functions for disks recently. First off setting the disk drive letter.

function set-driveletter {            
[CmdletBinding()]            
param (            
 [string]$computer=".",            
             
 [parameter(Mandatory=$true)]            
 [string]            
 [ValidatePattern("^[A-Z]{1}:{1}`$")]            
 $olddrive,            
             
 [parameter(Mandatory=$true)]            
 [string]            
 [ValidatePattern("^[A-Z]{1}:{1}`$")]            
 $newdrive            
              
)            
            
Get-WmiObject -Class Win32_Volume -ComputerName $computer -Filter "DriveLetter='$olddrive'" |             
Set-WmiInstance -Arguments @{DriveLetter=$newdrive}            
}

The difficult bit was getting the regular expression correct. It tests that we have a single letter and a colon.  The old and new drives are mandatory parameters

Simple call to Get-WmiObject and pipe to Set-WmiInstance.

Use it like this:

set-driveletter -olddrive z: -newdrive i:  

 

Jobs a good un.


August 4, 2011  1:40 PM

Authentication, Impersonation and Privileges

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

So, you want to use a new WMI namespace you have discovered that lets you work with IIS.

PS> Get-WmiObject -Namespace ‘root\webadministration’ -List -ComputerName web01
Get-WmiObject : Access denied
At line:1 char:14
+ Get-WmiObject <<<<  -Namespace ‘root\webadministration’ -List -ComputerName web01
    + CategoryInfo          : NotSpecified: (:) [Get-WmiObject], ManagementException
    + FullyQualifiedErrorId : System.Management.ManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

OK not good.

First thing to try is running PowerShell with elevated privileges – Right click and Run as Adminsitartor.

Nope – still not working

Secondly lets try –EnableAllPrivileges

PS > get-help get-wmiobject -Parameter EnableAllPrivileges

-EnableAllPrivileges [<SwitchParameter>]
   Enables all the privileges of the current user before the command makes the WMI call.

    Required?                    false
    Position?                    named
    Default value
    Accept pipeline input?       false
    Accept wildcard characters?  false

This means that the system recognises our credentials and the privileges we get from them e.g, we are an administrator.

Bad news is that doesn’t do any good. Time to look at the documentation. The IIS provider requires packet privacy which means we need to use the –Authentication parameter.

PS > get-help get-wmiobject -Parameter Authentication

-Authentication <AuthenticationLevel>
    Specifies the authentication level to be used with the WMI connection. Valid values are:

    -1: Unchanged
    0: Default
    1: None (No authentication in performed.)
    2: Connect (Authentication is performed only when the client establishes a relationship with the application.)
    3: Call (Authentication is performed only at the beginning of each call when the application receives the request.)
    4: Packet (Authentication is performed on all the data that is received from the client.)
    5: PacketIntegrity (All the data that is transferred between the client  and the application is authenticated and v
    erified.)
    6: PacketPrivacy (The properties of the other authentication levels are used, and all the data is encrypted.)

    Required?                    false
    Position?                    named
    Default value
    Accept pipeline input?       false
    Accept wildcard characters?  false

Get-WmiObject -Namespace ‘root\webadministration’ -List -ComputerName web01 -Authentication 6

This works BUT you still need to have started PowerShell with elevated privileges.

What happened?

We got caught by WMI providers author. They decided it would be a good idea if the data transmitted was encrypted. 

The various values for the authentication parameter are outlined in the table

Value

Meaning

-1

Unchanged – authentication remains as it was before

0

Default COM authentication level. Authentication is negotiated. WMI uses default Windows Authentication setting. The None setting (1) is never the result of a negotiated authentication.

1

None. No COM authentication in performed.

2

Connect. COM authentication is performed only when the client establishes a relationship with the server. No further checks are performed.

3

Call. COM authentication is performed only at the beginning of each call when the sever receives the request. Only packet headers are signed. No data is encrypted.

4

Packet. COM authentication is performed on all the data that is received from the client. Only packet headers are signed. No data is encrypted

5

PacketIntegrity. All the data that is transferred between the client and the application is authenticated and verified. All packets are signed. No data is encrypted.

6

PacketPrivacy. The properties of the other authentication levels are used, and all the data is encrypted.

These are DCOM authentication levels. DCOM is the transport mechanism for accessing remote machines

Most of the time we don’t need to worry about –Authentication but the most common value if we do will be to use packet privacy

These values are contained in the System.Management.Authenticationlevel enumeration

PS > [enum]::GetNames("System.Management.Authenticationlevel")
Default
None
Connect
Call
Packet
PacketIntegrity
PacketPrivacy
Unchanged

So we can do this

Get-WmiObject -Namespace ‘root\webadministration’ -List -ComputerName web01 `
-Authentication ([System.Management.Authenticationlevel]::Packetprivacy)

OR

Get-WmiObject -Namespace ‘root\webadministration’ -List -ComputerName web01 `
-Authentication Packetprivacy

to make the command more readable.

If you think you have a problem with the authentication level try this test

[enum]::GetNames("System.Management.Authenticationlevel") |
foreach {"`n$_"; Get-WmiObject -Namespace ‘root\webadministration’
-List -ComputerName web01 -Authentication $_}

You will get Access Denied messages for all but the packet privacy level.

The last part of the puzzle is Impersonation

PS > Get-Help get-wmiobject -Parameter Impersonation

Impersonation <ImpersonationLevel>
    Specifies the impersonation level to use. Valid values are:

    0: Default (reads the local registry for the default impersonation level , which is usually set to "3: Impersonate"
    .)
    1: Anonymous (Hides the credentials of the caller.)
    2: Identify (Allows objects to query the credentials of the caller.)
    3: Impersonate (Allows objects to use the credentials of the caller.)
    4: Delegate (Allows objects to permit other objects to use the credentials of the caller.)

    Required?                    false
    Position?                    named
    Default value
    Accept pipeline input?       false
    Accept wildcard characters?  false

The Impersonate (3) level is what we want. Anonymous isn’t actually used by WMI and Identify usually only allows the checking of access controls.

Delegation is a security risk and isn’t recommended as it can be used to access resources on other systems from the target.

To check the local registry look in 

Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\WBEM\Scripting -Name "Default Impersonation Level"

while you are doing that check out

Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\WBEM\Scripting -Name "Default Namespace"

as well

In addition to the IIS provider the Microsoft Cluster Services WMI provider also need packet privacy.

Next time you get an Access Denied

  1. Check running PowerShell with elevated privileges
  2. Try –EnableAllPrivileges
  3. Test against various authentication levels (my feeling is to always go to packet privacy as it seems to be that or the default)
  4. Check the Impersonation level

If that doesn’t work – leave a comment here and I’ll try and help


Forgot Password

No problem! Submit your e-mail address below. We'll send you an e-mail containing your password.

Your password has been sent to: