PowerShell for Windows Admins


September 4, 2011  3:32 AM

Setting AD logging

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Now that we know what the options are we can look at switching them on.

function set-logsetting{             
[CmdletBinding(SupportsShouldProcess=$true)]             
param (             
[parameter(Position=0,            
   Mandatory=$true,            
   ValueFromPipeline=$true,             
   ValueFromPipelineByPropertyName=$true)]            
   [string]$computer,            
               
   [string]$setting,            
               
   [ValidateRange(0,5)]            
   [int]$level             
)             
BEGIN{            
 $HKLM = 2147483650            
}#begin             
            
PROCESS{            
 if ($logtype.Values -notcontains $setting){            
   Throw "Incorrect setting - please use get-logsettingoptions"            
 }            
             
 $reg = [wmiclass]"\\$computer\root\default:StdRegprov"            
            
 $key = "SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics"            
             
 switch ($computer){            
   "."         {$computername = $env:COMPUTERNAME}            
   "localhost" {$computername = $env:COMPUTERNAME}            
   default     {$computername = $computer}            
 }            
             
 $result = $reg.SetDwordValue($HKLM, $key, $setting, $level)  ## REG_DWORD            
            
}#process             
END{}#end            
            
<# 
.SYNOPSIS
Sets AD diagnostic logging levels 

.DESCRIPTION
Sets AD diagnostic logging levels 

.PARAMETER  Computer
Computer Name

.PARAMETER  Setting
The setting to be logged

.PARAMETER  Level
The level of logging to be applied

.EXAMPLE
set-logsetting -computer server02 -setting "5 Replication Events" -level 1

.EXAMPLE
get-logsettingoptions | 
foreach {set-logsetting -computer server02 -setting $_ -level 2}

.EXAMPLE
get-logsettingoptions | 
where {$_ -like "19*"} | 
foreach {set-logsetting -computer server02 -setting $_ -level 5}

.LINK

http://support.microsoft.com/kb/314980

#>            
            
}

The setting and level are input as parameters. The level can be checked as a range – the setting to log is checked against the hash table of logging types. The WMI SetDWord method is used to perform the change. A few of the ways the setting to use can be input are shown in the help examples.

September 3, 2011  1:31 PM

Logging options

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

With 24 logging options to choose from its difficult to keep track of them. We already have the data in a ash table so lets just display it

function get-logsettingoptions{             
PROCESS{            
              
 1..$logtype.Count |            
 foreach {            
  $logtype["$_"]            
 }            
            
}#process             
END{}#end            
            
<# 
.SYNOPSIS
Displays logging options

.DESCRIPTION
Displays logging options

.EXAMPLE
get-logsettingoptions

#>            
            
}

A simple loop through the hash table and we get this display

1 Knowledge Consistency Checker

2 Security Events

3 ExDS Interface Events

4 MAPI Interface Events

5 Replication Events

6 Garbage Collection

7 Internal Configuration

8 Directory Access

9 Internal Processing

10 Performance Counters

11 Initialization/Termination

12 Service Control

13 Name Resolution

14 Backup

15 Field Engineering

16 LDAP Interface Events

17 Setup

18 Global Catalog

19 Inter-site Messaging

20 Group Caching

21 Linked-Value Replication

22 DS RPC Client

23 DS RPC Server

24 DS Schema

We can filter down the results using where-object or just copy the names to use when we set the logging options


September 3, 2011  6:09 AM

Book offers

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

 

Manning has a good offer on its books this weekend

Saturday, September 3: Save 50% on all eBooks.
Sunday, September 4 : Save 50% on all print books.
Monday, September 5 : Save 50% on your entire purchase.

see www.manning.com for details


September 3, 2011  5:18 AM

Active Directory Logging

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

I had a problem come up recently where I needed to check the level of logging applied to the AD database. This is configurable via registry settings. See http://support.microsoft.com/kb/314980 for details.

Checking one machine is OK by RDP but when you want to check a set of machines its time to dig out the PowerShell.  While I was at it I decided I might as well create a set of functions that:

  1. Check the log settings
  2. Clear all log settings
  3. Set individual log settings

We are dealing with 24 values in the registry so I need to have those available in a variable. I also need to deal with 5 possible logging levels. I originally thought of using enums (my new shiny toy) but the value names have spaces so that didn’t work.  Plan B is hash tables as shown below

$logtype = DATA {            
ConvertFrom-StringData -StringData @'
 1 = 1 Knowledge Consistency Checker
 2 = 2 Security Events
 3 = 3 ExDS Interface Events
 4 = 4 MAPI Interface Events
 5 = 5 Replication Events
 6 = 6 Garbage Collection
 7 = 7 Internal Configuration
 8 = 8 Directory Access
 9 = 9 Internal Processing
 10 = 10 Performance Counters
 11 = 11 Initialization/Termination
 12 = 12 Service Control
 13 = 13 Name Resolution
 14 = 14 Backup
 15 = 15 Field Engineering
 16 = 16 LDAP Interface Events
 17 = 17 Setup
 18 = 18 Global Catalog
 19 = 19 Inter-site Messaging
 20 = 20 Group Caching
 21 = 21 Linked-Value Replication
 22 = 22 DS RPC Client
 23 = 23 DS RPC Server
 24 = 24 DS Schema
'@            
}            
            
$loglevel = DATA {            
ConvertFrom-StringData -StringData @'
 0 = None
 1 = Minimal
 2 = Basic
 3 = Extensive
 4 = Verbose
 5 = Internal
'@            
}             
            
            
            
## functions            
. $psScriptRoot/Get-LogSetting.ps1            
            
            
Export-ModuleMember -Function * -Variable logtype, loglevel

By default variables don’t export from modules so I need to force that with Export-ModuleMember

The function to get the logging levels is this

function get-logsetting{             
[CmdletBinding(SupportsShouldProcess=$true)]             
param (             
[parameter(Position=0,            
   Mandatory=$true,            
   ValueFromPipeline=$true,             
   ValueFromPipelineByPropertyName=$true)]            
   [string]$computer             
)             
BEGIN{            
 $HKLM = 2147483650            
}#begin             
            
PROCESS{            
 $reg = [wmiclass]"\\$computer\root\default:StdRegprov"            
            
 $key = "SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics"            
             
 1..$logtype.Count |            
 foreach {            
  $value = $logtype["$_"]            
  $level = $reg.GetDwordValue($HKLM, $key, $value)  ## REG_DWORD            
              
  New-Object -TypeName PSObject -Property @{            
    Name = $value            
    Level = $loglevel["$($level.uValue)"]            
  }            
}            
            
}#process             
END{}#end            
            
}

The computer name comes in as a mandatory parameter. Then we get the WMI class for the registry and set the key. The values are found by looping through the $logtype hashtable. The results are displayed via an object.

I might add the computer name to the object & I need to create some help before publishing as part of the PAM modules


September 1, 2011  11:27 AM

PowerShell Deep Dive abstracts

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

With the Deep Dive just over 6 weeks away the programme is shaping up.Abstracts of some of the sessions can be viewed

http://blogs.msdn.com/b/powershell/archive/2011/09/01/8-abstracts-for-the-powershell-deep-dive-in-frankfurt.aspx

 

I will also be doing a session on working with events in PowerShell – WMI, .NET and the PowerShell engine

The discounted registration is open until 6 September  – see http://blogs.msdn.com/b/powershell/archive/2011/08/02/extending-discounted-registration-amp-session-proposal-deadline.aspx for details.

 

This is going to be a fantastic event – if you use PowerShell you need to be there


August 30, 2011  12:51 PM

Webcast: Get the most from PowerShell and WMI

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

I will be presenting the above webcast next week.

Date: Wednesday, September 7, 2011

Time: 12:00 PM – 1:00 PM CST

 

Thats 6pm UK time

 

Register for the web cast at

http://powershell.com/cs/media/p/11256.aspx


August 30, 2011  12:41 PM

Testing services

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

A forum question about testing services and if they weren’t running got me thinking. I created an function to solve the question

function test-service{             
[CmdletBinding(SupportsShouldProcess=$true)]             
param (             
[parameter(Position=0,            
   ValueFromPipeline=$true,             
   ValueFromPipelineByPropertyName=$true)]            
   [Alias("CN", "ComputerName")]              
   [string]$computer="." ,            
               
   [string]$service="BITS" ,            
               
[parameter(Mandatory=$true)]            
   [string]$file            
               
)             
BEGIN {            
 if (!(Test-Path -Path $file)){Throw "log file not found"}            
}            
PROCESS {            
$result =  Get-WmiObject -Class Win32_Service -ComputerName $computer -Filter "Name='$service'"            
            
Write-Verbose "$($result.State)"            
            
if ($($result.State) -eq "Running"){            
  $logdata = "{0,14} {1} {2}" -f $computer, $($result.State), (get-date -Format f )            
}            
else{             
 $start = $result.StartService()             
 if ($start.ReturnValue -eq 0){            
   $logdata = "{0,14} {1} {2}" -f $computer, "Service Started", (get-date -Format f )            
 }            
 else {            
  $logdata = "{0,14} {1} {2}" -f $computer, "Service FAILED to Start", (get-date -Format f )            
 }              
}            
Add-Content -Path $file -Value $logdata             
}            
} ## end function

But I don’t like the answer for a number of reasons:

  • end up out putting text
  • log files involve extra work in parsing
  • will other people know where the log file is

A better solution, in my mind, is to write the data to the event log.  In this case I would use the system log because we are testing services. The application log could be used or we could even create a specific event log for the purpose.

 

function test-service2{             
[CmdletBinding(SupportsShouldProcess=$true)]             
param (             
[parameter(Position=0,            
   ValueFromPipeline=$true,             
   ValueFromPipelineByPropertyName=$true)]            
   [Alias("CN", "ComputerName")]              
   [string]$computer="." ,            
               
   [string]$service="BITS"            
)             
PROCESS {            
$result =  Get-WmiObject -Class Win32_Service -ComputerName $computer -Filter "Name='$service'"            
            
Write-Verbose "$($result.State)"            
            
if ($($result.State) -eq "Running"){            
  $type = "Information"            
  $msg = "$computer - $service is $($result.State) "            
}            
else{             
 $start = $result.StartService()             
 if ($start.ReturnValue -eq 0){            
   $type = "Warning"            
   $msg = "$computer - $service  was started "            
 }            
 else {            
   $type = "Error"            
   $msg = "$computer - $service  FAILED to start"            
 }              
}            
Write-EventLog -LogName Application -Source ServiceTest -EntryType $type -Message $msg -EventId 9999            
            
}            
} ## end function

 

before using the function run this to create the event log source

New-EventLog -LogName Application -Source ServiceTest

The actions are all written to the event log as information, Warning or Error messages as appropriate.

Get-EventLog -LogName Application -Source ServiceTest

Shows the messages.

Enjoy


August 29, 2011  3:05 AM

Deal of the Day–PowerShell

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

PowerShell and WMI is Manning’s deal of the day – 50% off print or e-book.

 

The deal also extends to PowerShell in Practice and PowerShell in Action 2E

See www.manning.com for details


August 28, 2011  1:39 PM

Reminder: TechEd Australia PowerShell conference

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

The TechEd Australia PowerShell conference starts tomorrow at midnight UK time (9am in Australia).  Details from

http://msmvps.com/blogs/richardsiddaway/archive/2011/08/22/teched-australia-powershell-conference.aspx

 

I will be presenting on WSMAN and WMI


August 28, 2011  1:28 PM

Network Adapter vendors

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

The NDis WMI classes expose some information about the vendors that produce the various adapters in our systems

function get-adaptervendor {            
param(            
 [string]$computer="."            
)            
Get-WmiObject -Namespace root\wmi -Class MSNdis_CoVendorDescription `
-ComputerName $computer |            
foreach {            
                
  $id = Get-WmiObject -Namespace root\wmi  `
  -Class MSNdis_CoVendorId -ComputerName $computer `
  -Filter "InstanceName='$($_.InstanceName)'"            
            
  New-Object -TypeName PSobject -Property @{            
    Computer = $_.__SERVER            
    Adapter = $_.InstanceName            
    Active = $_.Active            
    Description = $_.NdisCoVendorDescription            
    Vendorid = $id.NdisCoVendorID            
  }            
}            
}


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: