PowerShell for Windows Admins


May 12, 2010  3:06 PM

WMI and the Registry



Posted by: Richard Siddaway
PowerShell v2, Registry, WMI

We can use WMI to access the registry on local and remote machines – if you remember back to VBScript it was the way to access the registry.

In PowerShell we have a couple of PowerShell drives available  through the provider

Name           Used (GB)     Free (GB) Provider      Root
—-           ———     ——— ——–      —-
HKCU                                   Registry      HKEY_CURRENT_USER
HKLM                                   Registry      HKEY_LOCAL_MACHINE

These only work with the local machine.  We can use PowerShell remoting to access the registry but if PowerShell isn’t installed we are back to WMI.

The class we need to use is StdRegprov

In Windows XP\2003 and earlier it is only found in the root\default namespace. In Windows Vista\2008 and above it is also found in the root\cimv2 namespace (which is the default namespace PowerShell uses). In order to access most machines we will work with the root\default instance. We need to use the [wmiclass] type accelerator

$reg = [wmiclass]\\.\root\default:StdRegprov

looking at $reg though get-member we see a lot of methods

CheckAccess
CreateKey
DeleteKey
DeleteValue
EnumKey
EnumValues
GetBinaryValue
GetDWORDValue
GetExpandedStringValue
GetMultiStringValue
GetQWORDValue
GetSecurityDescriptor
GetStringValue
SetBinaryValue
SetDWORDValue
SetExpandedStringValue
SetMultiStringValue
SetQWORDValue
SetSecurityDescriptor
SetStringValue

We will start looking at these next time

May 4, 2010  3:07 PM

String Substitution with WMI



Posted by: Richard Siddaway
PowerShell v2, WMI

String substitution is one of my favourite bits of PowerShell. If you’ve not seen it before the idea is that you can substitute a variable into a double quoted string.  Note that single quote strings won’t work. As an example

PS> $colour = “red”
PS> “The balloon is $colour”
The balloon is red
PS> ‘The balloon is $colour’
The balloon is $colour

One place this breaks down in when substituting properties of an object.  Consider something we’ve pulled back with WMI.

PS> $os = Get-WmiObject -Class Win32_OperatingSystem
PS> $os

SystemDirectory : C:\Windows\system32
Organization    :
BuildNumber     : 7600
RegisteredUser  : Richard
SerialNumber    : 00426-065-1155216-86852
Version         : 6.1.7600

We can pick off a couple of properties

PS> $os | select Caption, ServicePackMajorVersion | Format-List

Caption                 : Microsoft Windows 7 Ultimate
ServicePackMajorVersion : 0

 

We can use write-host

PS> Write-Host $os.Caption, $os.ServicePackMajorVersion
Microsoft Windows 7 Ultimate  0

 

and even expand it a bit

PS> Write-Host $os.Caption, “Service Pack”, $os.ServicePackMajorVersion
Microsoft Windows 7 Ultimate  Service Pack 0

but if we try string substitution

PS> Write-Host “The OS is $os.Caption with Service Pack $os.ServicePackMajorVersion”
The OS is \\RSLAPTOP01\root\cimv2:Win32_OperatingSystem=@.Caption with Service Pack \\RSLAPTOP01\root\cimv2:Win32_OperatingSystem=@.ServicePackMajorVersion

Oops – thats not what we want

The problem is that we are getting the object rather than the value.  We need to use a subexpression

PS> Write-Host “The OS is $($os.Caption) with Service Pack $($os.ServicePackMajorVersion)”
The OS is Microsoft Windows 7 Ultimate  with Service Pack 0

 

All this does is say give me the result of the expression in the brackets and substitute that in the string. Easy and neat. No need to concatenate strings to create the display line in your scripts.


May 3, 2010  1:05 PM

PowerShell UG May 2010



Posted by: Richard Siddaway
PowerShell v2, User Group
When: Tuesday, May 18, 2010 7:30 PM (BST)

Where: Live Meeting 

*~*~*~*~*~*~*~*~*~*

PowerShell eventing using WMI, .NET and the PowerShell engine

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:

  1. Copy this address and paste it into your web browser:

    https://www.livemeeting.com/cc/usergroups/join

  2. Copy and paste the required information:
    Meeting ID: 39Q7T9
    Entry Code: Q&x!_63dP
    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 2, 2010  10:06 AM

Ping, Ping, Ping



Posted by: Richard Siddaway
PowerShell v2, WMI

If you’ve used VBScript in the past you will remember using Win32_PingStatus to test the connectivity to a remote machine. In the 2010 Scripting Games we’ve seen a lot of scripts testing if a remote machine can be contacted.

Many of the scripts contain code of the form

$query = "Select * from Win32_PingStatus WHERE Address = ’127.0.0.1′"
Get-WmiObject -Query $query

There’s nothing wrong with this and it does the job so any marks for testing remote connectivity will be awarded. This code is a direct translation of the VBScript code.

The query could be given as part of the call to Get-WmiObject bit we can make it easier by doing this:

Get-WmiObject -Class Win32_PingStatus -Filter "Address = ’127.0.0.1′"

The query after the WHERE statement becomes  the filter and we give the class directly.  Bit less typing and easier to read.

if we want this as part of a loop where we will be testing multiple machines then we can refine it to this

$computer = ’127.0.0.1′
Get-WmiObject -Class Win32_PingStatus -Filter "Address = ‘$computer’"

The $computer variable could be set as part of the loop control rather than as a direct variable. One thing to be aware of is that computername parameter isn’t supported in the way most WMI classes support it

Note that this is NOT supported

Get-WmiObject -Class Win32_PingStatus -ComputerName $computer

In PowerShell v2 it gets even simpler as we have a cmdlet that wraps Win32_PingStatus for us

Test-Connection -ComputerName $computer

but it returns four pings by default so use

Test-Connection -ComputerName $computer -Count 1

All of the above work but the last one is the easiest and involves least typing (remember tab completion)


April 26, 2010  3:56 PM

Desktop of current logged on user



Posted by: Richard Siddaway
Users

 

In this post http://itknowledgeexchange.techtarget.com/powershell/current-logged-on-user/ we discovered how to find the current logged on user.  I want to extend that a bit and add the information about that users desktop.

We start with the script in our earlier post.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
## get session process
$proc = Get-WmiObject -Class Win32_SessionProcess | 
select Antecedent -First 1
$filt = ($proc -split "=")[2] -replace ‘"’,  -replace "}",""

$ltype = DATA {
ConvertFrom-StringData -StringData @’
0 = System
2 = Interactive
3 = Network
4 = Batch
5 = Service
6 = Proxy
7 = Unlock
8 = NetworkCleartext
9 = NewCredentials
10 = RemoteInteractive
11 = CachedInteractive
12 = CachedRemoteInteractive
13 = CachedUnlock
‘@

}
## get logon session
$sess = Get-WmiObject -Class Win32_LogonSession -Filter "LogonId=’$filt’"

## get user
$query = "ASSOCIATORS OF {Win32_LogonSession.LogonId=’$filt’}" `
            + "WHERE ResultClass=Win32_UserAccount"
$user = Get-WmiObject -Query  $query

$query2 = "ASSOCIATORS OF {Win32_UserAccount.Domain=’$($user.Domain)’" `
  + ",Name=’$($user.Name)’} WHERE ResultClass=Win32_Desktop"

$desktop = Get-WmiObject -Query $query2
 
Add-Member -InputObject $sess -MemberType NoteProperty -Name User `
   -Value $($user.Caption) -PassThru |
Format-List AuthenticationPackage, LogonId,
@{Name="Logon Type"; Expression = {$ltype["$($_.LogonType)"]}},
@{Name="Time"; Expression = {$_.ConvertToDateTime($_.StartTime)}},
User
"Desktop Settings:"
$desktop | Format-List BorderWidth, Caption, CoolSwitch,
CursorBlinkRate, Description, DragFullWindows,
GridGranularity, IconSpacing, IconTitleFaceName,
IconTitleSize, IconTitleWrap, Name, Pattern,
ScreenSaverActive, ScreenSaverExecutable,
ScreenSaverSecure, ScreenSaverTimeout,
SettingID, Wallpaper, WallpaperStretched,
WallpaperTiled

We add a query to get the desktop associated with the current user  – - $query2

That query returns the information about the desktop. Its displayed after the user information and I’ve selected the items I want to display.

This is a good example of extending an existing script when you find out how to do a bit more digging.

I think we’ve about exhausted the WMI information on users and groups for now – so its time to find another topic.


April 25, 2010  9:35 AM

PowerShell Admin Modules



Posted by: Richard Siddaway
PowerShell v2, PSAM, Shares

I have created the first download for the PowerShell Admin Modules. This will be a set of of modules including code previously published on my blogs at:

http://msmvps.com/blogs/RichardSiddaway/Default.aspx

http://itknowledgeexchange.techtarget.com/powershell/

http://richardsiddaway.spaces.live.com/

 

The first release comprises a module for working with shares and can be found at:

http://psam.codeplex.com/

 

It has the following functions:

  • Get-Share
  • Get-ShareAccessMask
  • Get-ShareSecurity
  • New-Share
  • Remove-Share
  • Set-Share

There have been a series of posts on my IT Knowledge Exchange blog (see above) about the functions.  Select Shares from the

Browse This Blog’s Tags box

More to follow soon. Enjoy

Technorati Tags: ,,,


April 24, 2010  3:32 PM

Windows Groups



Posted by: Richard Siddaway
PowerShell v2, Users, WMI

 

We can find the groups on a machine using WMI

PS> Get-WmiObject -Class Win32_Group | select Name, Description, SID, LocalAccount | format-list

Name         : Administrators
Description  : Administrators have complete and unrestricted access to the computer/domain
SID          : S-1-5-32-544
LocalAccount : True

etc etc

But what would be good would if we could also check membership at the same time

 

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
Get-WmiObject -Class Win32_Group | 
foreach {
    “`n$($_.Name)”
    “$($_.Description)”
    “SID: $($_.SID)”
    “Local = $($_.LocalAccount)”
    “Members:”
   
    $query = “ASSOCIATORS OF {Win32_Group.Domain=’” `
    + $_.Domain + “‘,Name=’” + $_.Name `
     + “‘} WHERE ResultClass=Win32_UserAccount”   
    Get-WmiObject -Query $query | 
    select Caption

}

By now this format should be familiar.  We get the groups and for each group we use the ASSOCIATORS query to find the group members using the  Win32_UserAccount. We use string substitution to display the group information and display the caption property to get the domain and user name


April 23, 2010  2:25 PM

Binging PowerShell



Posted by: Richard Siddaway
PowerShell v2

I posted recently about PowerShell help information being available in the Visual Search galleries on Bing – http://msmvps.com/blogs/richardsiddaway/archive/2010/04/19/powershell-on-bing.aspx

The URLs are available to find this directly.  For the time being its only available on the US version of Bing but if you are using PowerShell v2 you can do this

if ($psculture -ne "en-US") {Start-Process http://go.microsoft.com/fwlink/?LinkID=190436}
else {Start-Process "http://www.bing.com/visualsearch?mkt=en-us&g=powershell_cmdlets"}

The culture is checked to see if you are in the US and if so you are pointed straight to Bing. otherwise you are directed to the US version of Bing. As the PowerShell reference is rolled out on other versions of Bing you can always alter the comparison to test your culture – change it to $psuiculture which will probably return en-US.

Technorati Tags: ,,


April 23, 2010  2:04 PM

User Profiles



Posted by: Richard Siddaway
PowerShell v2, Users

 

Last time we looked at getting the currently logged on user. This time we’ll discover the user profiles that have been defined on our system.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
Get-WmiObject -Class Win32_UserProfile | 
foreach {
    $query =  “ASSOCIATORS OF {Win32_SID.SID=’” `
    + $_.Sid + “‘} WHERE ResultClass=Win32_SystemAccount”
     
    $trustee = Get-WmiObject -Query $query 
      
    if($trustee -eq $null){
        $query =  “ASSOCIATORS OF {Win32_SID.SID=’” `
        + $_.Sid + “‘} WHERE ResultClass=Win32_UserAccount”
        $trustee = Get-WmiObject -Query $query 
    }
    Add-Member -InputObject $_ -MemberType NoteProperty -Name User `
    -Value $($trustee.Caption) -PassThru
} |
Format-List User, Loaded, LocalPath, RoamingConfigured, RoamingPath,
RoamingPreference, Special, Status,
@{Name=“Last Download”; 
 Expression={$_.ConvertToDateTime($_.LastDownloadTime)}},
@{Name=“Last Upload”; Expression={$_.ConvertToDateTime($_.LastUploadTime)}},
@{Name=“Last Used”; Expression={$_.ConvertToDateTime($_.LastUseTime)}}

We use Win32_UserProfile and foreach we find the user account associated with the SID – this is lifted straight from our look at share permissions. We use the technique from last time to add a property to the current object only this time are using the pipeline object (originally from our WMI query).

We can then pipe into Format-List and perform our display including converting the dates.

This class only appears to be available on Windows Vista SP1 and above – see http://msdn.microsoft.com/en-us/library/ee886409(VS.85).aspx for details.


April 22, 2010  3:08 PM

Current logged on user



Posted by: Richard Siddaway
PowerShell v2, Users

in case you are wondering how I pick the topics for these posts – its quite scientific.  I run

Get-WmiObject -List win32* | where {$_.Name -notlike “*perf*”}

to see the available classes and pick something that catches my eye. Sometimes it leads to a series of posts and other times its a single post.

This time my eye was caught by Win32_LogonSession – which returns the logged on user

PS> Get-WmiObject -Class Win32_LogonSession

AuthenticationPackage : NTLM
LogonId               : 188568
LogonType             : 2
Name                  :
StartTime             : 20100422181039.691600+060
Status                :

AuthenticationPackage : NTLM
LogonId               : 188537
LogonType             : 2
Name                  :
StartTime             : 20100422181039.691600+060
Status
                :

OK thats not good ‘cos I know I’m the only one logged in – unless its my imaginary friend

PS> Get-WmiObject -Class Win32_SessionProcess | select Antecedent

Antecedent
———-
\\.\root\cimv2:Win32_LogonSession.LogonId=”188568″
\\.\root\cimv2:Win32_LogonSession.LogonId=”188568″

etc

Shows that LogonId 188568 is the latest as Win32_SessionProcess shows the processes associated with the current logged on user.

We need to take that fact and find the logged on user

 

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
## get session process
$proc = Get-WmiObject -Class Win32_SessionProcess | 
select Antecedent -First 1
$filt = ($proc -split “=”)[2] -replace ‘”‘,  -replace “}”,“”

$ltype = DATA {
ConvertFrom-StringData -StringData @’
0 = System
2 = Interactive
3 = Network
4 = Batch
5 = Service
6 = Proxy
7 = Unlock
8 = NetworkCleartext
9 = NewCredentials
10 = RemoteInteractive
11 = CachedInteractive
12 = CachedRemoteInteractive
13 = CachedUnlock
‘@

}
## get logon session
$sess = Get-WmiObject -Class Win32_LogonSession -Filter “LogonId=’$filt’”

## get user
$query = “ASSOCIATORS OF {Win32_LogonSession.LogonId=’$filt’} `
WHERE ResultClass=Win32_UserAccount”

$user = Get-WmiObject -Query  $query
 
Add-Member -InputObject $sess -MemberType NoteProperty -Name User `
 -Value $($user.Caption) -PassThru |
Format-List AuthenticationPackage, LogonId,
@{Name=“Logon Type”; Expression = {$ltype["$($_.LogonType)"]}},
@{Name=“Time”; Expression = {$_.ConvertToDateTime($_.StartTime)}},
User

We take our session process – select first 1 and we only need the Antecedent property. We then split it on a “=” sign and do 2 replaces to clean it up.  I was surprised when the operators combined like that.

The here-string defines a the logon types. We find the Win32_LogonSession associated with the logonid and then get the ASSOCIATORS to find the associated user.

We use Add-Member to add the user name property to the session information and then use a couple of calculated fields to display the logon type and the logon date


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: