Thursday, 13 June 2013

Pointers from Scripting Games 2013


The scripting games have just concluded with all 6 challenges drawing to a close. The games presented a wonderful learning opportunity along with helpful insights from expert judges and peers. The knowledge gained from reviewing other contributors' scripts and comments was immense. You can check the scripts and comments by following this link.

A few pointers that i picked up through the games are listed below: 


  • Full command and parameter names

Every challenge in the scripting games explicitly stated the preference for full command and parameter names instead of alias or abbreviations. It makes it easier for everyone to understand the script without much effort.


  • Formatting

Formatting the code with white spaces and tabs to create indents makes for easy reading.
This was important particularly in the beginner’s events where it was encouraged to write a one-liner. By introducing carriage returns and indents wherever possible, the integrity of a one liner is not broken and it is presented in a much better way.


  • Comment based help
I admit I had never considered including comment based help in my scripts before the scripting games. But after realizing its significance and due to encouragement from the community, it is a staple in my scripts now.

Don Jones also explains the concept here


  •  Requires
The #Requires tag can be used in scripts to annotate the powershell version necessary to execute the script. It is generally placed on top of the script.


  • Write-Host
Write-Host cmdlet is only capable of outputting data on screen. It does NOT write to pipeline. Almost every need to include the cmdlet can be replaced by either Write-Verbose or Write-Debug or Write-Error or Write-Warning or Write-Output.

That being said, Write-Host cmdlet’s ability to display colorful data on-screen using the –Foreground and –Background switches is unique.


  • Format* commands
Similar to Write-Host, format commands are also the last one in the pipeline. It can display data on screen and there can be no further data manipulation.


  • Filtering on server side
When querying data specially from a remote computer, it is always better to filter data on the server and then retrieve them. The script’s execution time reduces considerably.


  • Error handling
Error handling was another important feature that was emphasized in the games, notably in the advanced challenges. Try/Catch/Finally blocks can be an effective method to include the same within scripts.

Refer the following links for further information:



  • Use native Powershell commands and naming conventions.
Using native powershell commands, as much as possible, is also generally considered as good practice.


Tuesday, 28 May 2013

Eliminate Ellipsis In Powershell


When trying to display the result of some queries on screen, we may find that some of the output is truncated by ellipsis i.e. “ . . .” , often the case with multi-valued attributes. An example of the ellipsis can be found when retrieving the thread details of any process. The image below shows the output when querying the thread details for system process:

Get-Process System | select Name,Threads




The reason that the thread column gets truncated at 4 values is because of $FormatEnumerationLimit. Help about the variable can be found under About_Preference_Variables. The value is set at 4 by default in the powershell console and the value is 16 in the exchange shell.











The entire thread details can be listed by modifying the above command to:

Get-Process System | select Name,Threads | ft –Wrap –Autosize



An alternate method to display the threads would be to use the ‘ExpandProperty’ switch in Select-Object cmdlet:

get-process system | Select-Object Name -ExpandProperty Threads | ft Name, ID –AutoSize




The easiest method would be to change the default value of the $FormatEnumerationLimit.

The default value has been altered to 80 which displays the whole list of system threads on screen:



Tuesday, 21 May 2013

Scripting Games - Beginner Event 4


The Scripting Games has been discussed in the previous post. The games are now four events old.  Event 4 of the Beginners track posed the challenge below:

Dr. Scripto isn’t saying that he dislikes auditors, but they do seem to show up at the most inconvenient times—and with the oddest requests. So he’s tossing this particular auditor request over to you.

This auditor would like a report that shows 20 randomly selected (well, as random as you can get) users from Active Directory. For each user, the auditor wants to see their user name, their department and title, and the last time they logged on. You also need to show the date their password was last changed, and whether the account is disabled or locked out. So that’s seven pieces of information. You’re to put that information into an HTML-based report file, and the file must show the date and time that the report was generated. Please make sure that all of the dates are normal looking, human-readable dates and times.

Keep your command as concise as possible, although that doesn’t mean you’re not allowed to use full command and parameter names—that’s always okay to do! A domain admin will always run the command, and the resulting HTML file will be manually emailed to the requesting auditor.

My solution for the event was:

Import-module ActiveDirectory

Get-ADUser -Filter * -Properties Name,Department,Title,LastLogonDate,PasswordLastSet,LockedOut,Enabled | get-random -count 20 | select Name,Department,Title,PasswordLastSet,LastLogonDate,LockedOut,Enabled | ConvertTo-Html -PostContent "<hr>","Report Generated at : ", (get-date) | Set-Content "C:\Users Report.htm"

The first line imports the ActiveDirectory module with the assumption that the module is not pre-loaded. The ‘Properties’ switch in Get-ADUser switch specifies the user attributes to be retrieved that are not displayed by default; ex: Dpartment, Title, LastLogonDate.  ‘Get-Random’ command in the pipeline outputs random 20 users.  The required properties are then selected and the output is converted to HTML and saved on the local drive.

Helpful links:




Tuesday, 14 May 2013

Scripting Games - Beginner Event 3


The Scripting Games are a six week event that lets you showcase your scripting skills based on six challenges. You can either choose compete in the Advanced or the Beginner’s track. I have registered for the beginner’s event since it is my first year being part of the games. It is a great learning experience to see such diverse approaches on any challenge. If you haven’t registered yet, it’s not too late. Please follow the link below for more details:


The Games just concluded its third event. The beginner track event challenged the competitors to come up with a one liner for the below scenario:  

Dr. Scripto has been fielding a lot of calls from the Help Desk lately. They’ve been asking him to look up information about the local hard drives in various servers –mainly size and free space information. He doesn’t mind helping, but all the requests have been getting in the way of his naps. He’s asked you to write a one-liner command that can get the information for him – and he wants the output in an
HTML file.

















The Doctor says you don’t need to parameterize your command – it’s okay to write it to run against localhost, and he can just change that computer name as needed in the future. The resulting HTML does need to go into an HTML file on disk someplace, and he wants you to pay special attention to the following:


• The browser displays “Disk Free Space Report” in the page tab when viewing the report.
• “Local Fixed Disk Report” is in the H2 (“Heading 2”) HTML style.
• The report ends with an HTML horizontal rule and the date and time that the report was generated.
• The size and free space values are shown as gigabytes (GB) and megabytes (MB) respectively, each to two decimal places.

The command you write can assume that both WMI and CIM are available on the remote computers, and that all the necessary firewall rules and authentication have already been taken care of.


 The one-liner solution I came up for the challenge was:

Get-WmiObject -Class "win32_logicaldisk" -Computername "localhost"-Filter "Drivetype = 3" | Select-Object @{Name="Drive";Expression={$_.DeviceID}},@{Name="Size(GB)";Expression={"{0:N2}" -f ($_.Size/1GB)}},@{Name="FreeSpace(MB)";Expression={"{0:N2}" -f ($_.FreeSpace/1MB)}} | ConvertTo-Html -title "Drive Free Space Report" -precontent "<H2>Local Fixed Disk Report</H2>" -body $_  -postcontent "<hr>",(get-date) | Set-Content "C:\FreeDiskReport.htm"

The report generated using the above command:





Sunday, 12 May 2013

Working With Multi-Valued Attributes - Part 2

Part 1 of the series dealt with 'set' cmdlets with respect to multi-valued attributes.

Now in part 2, we are going to look at the challenges faced when retrieving multi-valued attributes using 'Get' cmdlets and workarounds for them. If the number of the values stored in the attribute is high, then displaying the entire list on screen is not possible as powershell tends to append the list with “. . . “ implying that there are more values in the property than displayed on screen.

Get-DistributionGroup "Test DL" | fl Name, AcceptMessagesOnlyFrom 



Exporting the values to a CSV/ text file is also a concern, since the actual values in the attribute are not exported to the file as seen below.

Get-DistributionGroup "Test DL" | Select-Object Name, AcceptMessagesOnlyFrom | Export-Csv "C:\DL.csv" -Notype







The  pipeline can be manipulated to export all the attributes as shown below:

 Get-DistributionGroup "Test DL"  | Select-Object Name,@{Name="AcceptMessagesOnlyFrom";Expression={[string]::join(";",$_.AcceptMessagesOnlyFrom)}} | Export-Csv c:\DL.csv –NoTypeInformation


The output is shown below : 

The text in image above has been altered to confine within the image size to display all the values contained in the CSV file.

Thursday, 9 May 2013

Working With Multi-Valued Attributes in Powershell - Part 1

Multi-valued attributes are attributes that can contain more than one value. Email-addresses of users, Accept messages only from attribute of Distribution groups are some examples of multi-valued attributes.  Modifying or retrieving single-valued attributes through shell are quite simple whereas caution needs to be exercised when dealing with multi-valued ones.  Powershell, by default, tends to replace a value instead of appending when Set commands are used. So multi-valued properties can be accidentally over-written..

Consider a distribution group ‘Test DL’ which is set to accept messages only from ‘User1’, ‘User2’ and ‘User3’. We can query the attribute using the command below :

Get-DistributionGroup "Test DL" | fl  Name,AcceptMessagesOnlyFrom




Now, when ‘User 4’ needs to be added to the same property we execute the command below:

Set-DistributionGroup "Test DL" -AcceptMessagesOnlyFrom 'User4'

However, when we execute the first command again, we find that the existing users have been replaced by ‘User4’




To avoid replacing the existing users, the below command can be used instead:

Set-DistributionGroup "Test DL" -AcceptMessagesOnlyFrom @{Add = "User4"}



To remove ‘User4’ from the accept messages only from parameter, the command can be altered to:

Set-DistributionGroup "Test DL" -AcceptMessagesOnlyFrom @{Remove = “User4”}




A single command can be used to remove ‘User1’ and add ‘User5’ to the attribute:

Set-DistributionGroup "Test DL" -AcceptMessagesOnlyFrom @{Remove = "User1" ; Add="User5"}



The general syntax would be:

Set-cmdlet ‘Identity ’-MultivaluedAttributeSwitch  @{Add = “value1”,”value2”,”value3” ; Remove = “value4”,”value5”}

Monday, 6 May 2013

Import Powershell Module From A Remote Machine


We've all had scenarios where we need to incorporate cmdlets in our script that are not available on the local machine. The cmdlets below will import the Exchange module from a remote server :

$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "http://ServerName/powershell" 
$mod = Import-PSSession $session


The first line creates a session to the Exchange server's powershell. Line 2 imports the session and load the AD module to the powershell console on the local machine, thus providing us access to the AD cmdlets.


"WARNING: Some imported command names include unapproved verbs which might make them less discoverable. Use the Verbose parameter for more detail or type Get-Verb to see the list of approved verbs."

The warning message is displayed by default when an imported module exports cmdlets or functions that have unapproved verbs in the name parameter. Although the message is displayed, the complete module along with the non conforming cmdlets are imported.



To supress the warning message, '-DisableNameChecking' switch can be added to the import command.




'Get-Command' can be used to list all the cmdlets available through the imported module:

Get-Command -Module $mod.Name



The script here assumes that the user has domain admin credentials. Credentials can be supplied explicitly by adding the '-credential ' switch :

$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "http://ServerName/powershell"  -Credential $cred