November 2012 - Posts

A switch in time

I’ve posted about the switch statement a number of times but it is one of those topics that keeps coming up. Imagine you have a variable that can take one of several values. Depending on the value you might want to perform different actions like this

"red", "blue", "white", "black", "green", "yellow" |            
foreach {            
$colour = $_            
            
if ($colour -eq "red"){Write-host "Apples can be red"}            
if ($colour -eq "blue"){Write-host "Balloons can be blue"}            
if ($colour -eq "white"){Write-host "Snow can be white"}            
if ($colour -eq "black"){Write-host "Coal can be black"}            
if ($colour -eq "green"){Write-host "Grass can be green"}            
if ($colour -eq "yellow"){Write-host "Custard can be yellow"}            
}

This is a whimsical example but my excuse is that its been a long week. 

The code compares the variable to a number of values and when it finds a match something happens – in this case some text is printed.

This code works but it is overly verbose and each and every if statement is executed which is inefficient

The switch statement was designed for this situation where you need to perform multiple comparisons

"red", "blue", "white", "black", "green", "yellow" |            
foreach {            
switch ($_){            
 "red"    {Write-host "Apples can be red"}            
 "blue"   {Write-host "Balloons can be blue"}            
 "white"  {Write-host "Snow can be white"}            
 "black"  {Write-host "Coal can be black"}            
 "green"  {Write-host "Grass can be green"}            
 "yellow" {Write-host "Custard can be yellow"}            
} # end of switch            
} # end of foreach

You define the variable you will test – in this case $_

The possible values are listed and the actions to take define in the script block.

This can be improved – what if a colour isn’t defined in the switch statement.  In this case you use the default statement to catch it

"red", "blue", "white", "black", "green", "yellow", "cyan" |            
foreach {            
switch ($_){            
 "red"    {Write-host "Apples can be red"}            
 "blue"   {Write-host "Balloons can be blue"}            
 "white"  {Write-host "Snow can be white"}            
 "black"  {Write-host "Coal can be black"}            
 "green"  {Write-host "Grass can be green"}            
 "yellow" {Write-host "Custard can be yellow"}            
 default {Write-Host "can't process $($_)"}            
} # end of switch            
} # end of foreach

One final improvement is to make the switch statement terminate once its made a match.  if you did this

"red", "blue", "white", "black", "green", "yellow", "cyan" |            
foreach {            
switch ($_){            
 "red"    {Write-host "Apples can be red"}            
 "blue"   {Write-host "Balloons can be blue"}            
 "white"  {Write-host "Snow can be white"}            
 "black"  {Write-host "Coal can be black"}            
 "green"  {Write-host "Grass can be green"}            
 "blue"   {Write-host "Bikes can be blue"}            
 "yellow" {Write-host "Custard can be yellow"}            
 default {Write-Host "can't process $($_)"}            
} # end of switch            
} # end of foreach

but really you want to stop the comparison when you get a match so you use the break keyword

"red", "blue", "white", "black", "green", "yellow", "cyan" |            
foreach {            
switch ($_){            
 "red"    {Write-host "Apples can be red"; break}            
 "blue"   {Write-host "Balloons can be blue"; break}            
 "white"  {Write-host "Snow can be white"; break}            
 "black"  {Write-host "Coal can be black"; break}            
 "green"  {Write-host "Grass can be green"; break}            
 "blue"   {Write-host "Bikes can be blue"; break}            
 "yellow" {Write-host "Custard can be yellow"; break}            
 default {Write-Host "can't process $($_)"}            
} # end of switch            
} # end of foreach

In this case the second test on “blue” won’t happen

Switch can get a lot more complicated than this so I recommend you read the help file

get-help about_switch

Posted by RichardSiddaway | with no comments
Filed under:

Active Directory & testing for user’s existence

 

When you are creating a new user you may want to test if a particular name is already is use. The Quest AD cmdlets provide great functionality but one area of confusion is where you are searching for a user by name:

PS> Get-QADUser -Identity "GREEN Dave" | ft -a

Name        Type DN
----        ---- --
GREEN Dave  user CN=GREEN Dave,CN=Users,DC=Manticore,DC=org
GREEN Dave2 user CN=GREEN Dave2,CN=Users,DC=Manticore,DC=org

But I didn’t ask for the second user. The problem is because the Quest cmdlets use s ANR – ambiguous name resolution when searching. This is equivalent to using "GREEN Dave*" in your search. In other words the cmdlets assume you are appending wildcards.

Way round it is to use an LDAP filter

PS> Get-QADUser -LdapFilter '(cn=GREEN Dave)' | ft -a

Name       Type DN
----       ---- --
GREEN Dave user CN=GREEN Dave,CN=Users,DC=Manticore,DC=org

LDAP filters are also available with the Microsoft cmdlets (you can’t use name as a search with the identity parameter with the MS cmdlets)

PS> Get-ADUser -LdapFilter '(cn=GREEN Dave)'


DistinguishedName : CN=GREEN Dave,CN=Users,DC=Manticore,DC=org
Enabled           : True
GivenName         : Dave
Name              : GREEN Dave
ObjectClass       : user
ObjectGUID        : 28f0c168-d142-417f-a223-333488cdaa77
SamAccountName    : dgreen
SID               : S-1-5-21-3881460461-1879668979-35955009-6270
Surname           : GREEN
UserPrincipalName : dgreen@manticore.org

All of these alternatives will work

Get-ADUser -LdapFilter '(name=GREEN Dave)'
Get-QADUser -LdapFilter '(name=GREEN Dave)'
Get-QADUser -LdapFilter '(name=green dave)'
Get-ADUser -LdapFilter '(name=green dave)'

As an additional bonus with the Microsoft cmdlets you can write the filter using PowerShell syntax

Get-ADUser -Filter {name -eq 'green dave'}

if you want to unambiguously resolve a name in an AD search – use an LDAP filter

Clearing all telephone information for an AD account

I had a question through the blog asking how you could clear the telephone, pager and ipphone information from a user account.

Telephone information in AD appears on the General tab telephone and Other..   And on the telephone tab there is home, mobile, pager, fax and ipphone each of which can have a number of Other phone numbers added

I thought it best to write a function that clears all telephone information.  That way you can pick out the bits you need.

function clear-telephoneInfo {            
[CmdletBinding()]            
param (            
 [parameter(ParameterSetName="ByDN")]            
 [string]$dn,            
 [parameter(ParameterSetName="ByName")]            
 [string]$name,            
 [parameter(ParameterSetName="ByName")]            
 [string]$ou            
)            
switch ($psCmdlet.ParameterSetName) {            
 "ByDN"  {$distname = $dn }            
 "ByName"  {$distname = "cn=$name,$ou" }            
 default {Write-Host "Error!!! Should not be here" }            
}            
            
## clear telephone from General tab            
$user = [adsi]"LDAP://$distname"            
$user.TelephoneNumber = ' '            
$user.otherTelephone = ' '            
$user.SetInfo()             
            
## clear Telephone tab            
## Home Phone            
$user = [adsi]"LDAP://$distname"            
$user.homePhone = ' '            
$user.otherHomePhone = ' '            
$user.SetInfo()             
            
## Pager            
$user = [adsi]"LDAP://$distname"            
$user.pager = ' '            
$user.otherPager = ' '            
$user.SetInfo()              
            
## Mobile            
$user = [adsi]"LDAP://$distname"            
$user.mobile = ' '            
$user.otherMobile = ' '            
$user.SetInfo()              
             
## Fax            
$user = [adsi]"LDAP://$distname"            
$user.facsimileTelephoneNumber = ' '            
$user.otherFacsimileTelephoneNumber = ' '            
$user.SetInfo()              
            
## Fax            
$user = [adsi]"LDAP://$distname"            
$user.ipPhone = ' '            
$user.otherIpPhone = ' '            
$user.SetInfo()            
            
## Notes            
$user = [adsi]"LDAP://$distname"            
$user.info = ' '            
$user.SetInfo()              
}

I created two parameter sets – one for the distinguished name (ByDN) and one where the name and OU are supplied.

The $distname parameter is set based on the parameter set.

An ADSI call gets the user; the telephoneNumber and othertelephone attributes are set to blank strings and the SetInfo() is called to write the changes back.

This is repeated for the other types of phone number and the Notes field on the telephone tab

I broke it up like this to make it easier to pick and choose what you need.  It would be possible to add more parameters to only pick off a particular type of phone number

UK PowerShell group – December 2012

Last meeting of 2012 – PowerShell jobs and scheduled tasks


 


When: Tuesday, Dec 4, 2012 7:30 PM (GMT)


Where:

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

PowerShell jobs provide the ability to perform long running background tasks. With the introduction of cmdlets to schedule tasks the possibilities increase

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: KRSN4M
    Entry Code: s`xS<XHp2
    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.

Powershell Resources on Skydrive

I’ve reorganised the slide packs and recordings for the UK PowerShell group. You can find them here

https://skydrive.live.com/?cid=43cfa46a74cf3e96!cid=43CFA46A74CF3E96&id=43CFA46A74CF3E96%2139273

Three folders:

  • Events – slides from events I’ve spoken at
  • Scripts
  • UK PowerShell Group
  •        Meeting Recordings – includes slide packs
  •        Slide packs – from older meetings where the recording isn’t available

Enjoy

Posted by RichardSiddaway | with no comments

Introduction to PowerShell workflows

The recording, slides and demo scripts from tonights session are available at

https://skydrive.live.com/#cid=43CFA46A74CF3E96&id=43CFA46A74CF3E96%2140260

Workflow session reminder

The re-scheduled UK PowerShell group session on workflows will happen tomorrow. Details from

http://msmvps.com/blogs/richardsiddaway/archive/2012/11/14/powershell-group-session.aspx

Kindle Fire quirk

Quick report of an oddity that I discovered with the Kindle Fire.  If you copy an ebook in mobi format onto the Fire you can read it with no problem.  If you select remove from device when you have finished reading the book it disappears from the list on books on the device. The file isn’t deleted though – you need to do that manually.

I’ve been using the Fire for a few weeks now and its an excellent travelling machine.

Posted by RichardSiddaway | with no comments
Filed under:

PowerShell Group Session

I seem to have fixed my audio problems so I’m re-scheduling the session


When: Tuesday, Nov 20, 2012 7:30 PM (GMT)


Where:

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

Workflows are one of the big things in PowerShell v3. This session provides an introduction and overview of this must know technology

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: 4KTZN9
    Entry Code: 3G~mgr.P9
    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.

Apologies for meeting failure

Apologies to all who tried to attend the Live Meeting tonight – I had audio problems that I couldn’t resolve.

I’ll reschedule the session when I’ve fixed the problem

Posted by RichardSiddaway | with no comments

New about files

PowerShell v3 features updateable help.  The help files are not quite complete at the moment but a recent update to the help that is available brought a couple of very useful files:

about_WMI

about_WQL

The first gives a good overview of WMI and the its structure.  Good background reading.

The second gives a very good start for using WMI Query Language – WQL.  It doesn’t cover everything – for instance associations are mentioned but it does give enough to work sensibly with WMI filters.

Both files are recommended reading

WMI –property parameter

One parameter that seems to get overlooked on Get-WmiObject is the –Property parameter. It is used to specify the properties you want returned.

This is what you would normally get by default:

PS> Get-WmiObject -Class Win32_Service  | select -f 1


ExitCode  : 0
Name      : AdobeARMservice
ProcessId : 1716
StartMode : Auto
State     : Running
Status    : OK

The full property list looks like this:

PS> Get-WmiObject -Class Win32_Service  | select -f 1 | fl *


PSComputerName          : RSLAPTOP01
Name                    : AdobeARMservice
Status                  : OK
ExitCode                : 0
DesktopInteract         : False
ErrorControl            : Ignore
PathName                : "C:\Program Files\Common Files\Adobe\ARM\1.0\armsvc.exe"
ServiceType             : Own Process
StartMode               : Auto
__GENUS                 : 2
__CLASS                 : Win32_Service
__SUPERCLASS            : Win32_BaseService
__DYNASTY               : CIM_ManagedSystemElement
__RELPATH               : Win32_Service.Name="AdobeARMservice"
__PROPERTY_COUNT        : 25
__DERIVATION            : {Win32_BaseService, CIM_Service, CIM_LogicalElement, CIM_ManagedSystemElement}
__SERVER                : RSLAPTOP01
__NAMESPACE             : root\cimv2
__PATH                  : \\RSLAPTOP01\root\cimv2:Win32_Service.Name="AdobeARMservice"
AcceptPause             : False
AcceptStop              : True
Caption                 : Adobe Acrobat Update Service
CheckPoint              : 0
CreationClassName       : Win32_Service
Description             : Adobe Acrobat Updater keeps your Adobe software up to date.
DisplayName             : Adobe Acrobat Update Service
InstallDate             :
ProcessId               : 1716
ServiceSpecificExitCode : 0
Started                 : True
StartName               : LocalSystem
State                   : Running
SystemCreationClassName : Win32_ComputerSystem
SystemName              : RSLAPTOP01
TagId                   : 0
WaitHint                : 0
Scope                   : System.Management.ManagementScope
Path                    : \\RSLAPTOP01\root\cimv2:Win32_Service.Name="AdobeARMservice"
Options                 : System.Management.ObjectGetOptions
ClassPath               : \\RSLAPTOP01\root\cimv2:Win32_Service
Properties              : {AcceptPause, AcceptStop, Caption, CheckPoint...}
SystemProperties        : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY...}
Qualifiers              : {dynamic, Locale, provider, UUID}
Site                    :
Container               :

You can restrict the properties returned:

PS> Get-WmiObject -Class Win32_Service  -Property SystemName, Name, DisplayName | select -f 1


__GENUS          : 2
__CLASS          : Win32_Service
__SUPERCLASS     :
__DYNASTY        :
__RELPATH        : Win32_Service.Name="AdobeARMservice"
__PROPERTY_COUNT : 3
__DERIVATION     : {}
__SERVER         :
__NAMESPACE      :
__PATH           :
DisplayName      : Adobe Acrobat Update Service
Name             : AdobeARMservice
SystemName       : RSLAPTOP01
PSComputerName   :

problem is you still get the system properties (those that start __ )

PS> Get-WmiObject -Class Win32_Service  -Property SystemName, Name, DisplayName | select -f 1 | fl SystemName, Name, DisplayName


SystemName  : RSLAPTOP01
Name        : AdobeARMservice
DisplayName : Adobe Acrobat Update Service

replace the format-list (fl) by another select if you want to do anything with the object.

The new CIM cmdlets in PowerShell v3 also have a property parameter

PS> Get-CimInstance -Class Win32_Service  -Property SystemName, Name, DisplayName | select -f 1

 

Name                    : AdobeARMservice
Status                  :
ExitCode                :
DesktopInteract         :
ErrorControl            :
PathName                :
ServiceType             :
StartMode               :
Caption                 :
Description             :
InstallDate             :
CreationClassName       :
Started                 :
SystemCreationClassName :
SystemName              : RSLAPTOP01
AcceptPause             :
AcceptStop              :
DisplayName             : Adobe Acrobat Update Service
ServiceSpecificExitCode :
StartName               :
State                   :
TagId                   :
CheckPoint              :
ProcessId               :
WaitHint                :
PSComputerName          :
CimClass                : root/cimv2:Win32_Service
CimInstanceProperties   : {Caption, Description, InstallDate, Name...}
CimSystemProperties     : Microsoft.Management.Infrastructure.CimSystemProperties

This only populates the select properties but displays all properties by default!

use select again to restrict

PS> Get-CimInstance -ClassName Win32_Service  -Property SystemName, Name, DisplayName | select -f 1 | fl SystemName, Name, DisplayName


SystemName  : RSLAPTOP01
Name        : AdobeARMservice
DisplayName : Adobe Acrobat Update Service

Either way – WMI or CIM – you have to do a bit more work but the important point is that only the properties you want are returned across the network. Reduces traffic and should boost performance.

Using a WQL query returns the results shown above. This is because the –Filter parameter is turned into a WQL query.

Honorary Scripting Guy

The Scripting Guy announced today that I have been awarded Honorary Scripting Guy status - http://blogs.technet.com/b/heyscriptingguy/archive/2012/11/04/announcing-the-2012-honorary-scripting-guys.aspx

This is a great honour for which I’m very grateful – thank you

Congratulations to the other awardees.

Posted by RichardSiddaway | 1 comment(s)
Filed under:

PowerShell summit sessions announced

The sessions for the PowerShell summit at the Microsoft campus in April 2013 have been announced.

http://poshoholic.com/2012/11/02/powershell-summit-community-sessions-list/

Posted by RichardSiddaway | with no comments
Filed under: ,