The 2013 Scripting Games started April 25th, and event 6 is now open for voting. This is the last event, and I must say I have learned a lot by reviewing scripts from all of the events. One of the great things about PowerShell is that there are many ways to perform a task, and by seeing how others solves it is a great learning opportunity. As I did in the previous events, I will pick out two entries from each event and provide some learning points to highlight both good and bad practices.
Before reading my comments, you might want to download the event instructions:
The first entry I will comment on is from Beginner 6:
The #requires statement is used to ensure that version 3.0 of PowerShell is being used when executing the script. This is good since functionality only available in version 3.0 is leveraged, such as the DHCP Server module.
- The #requires statement could also have been used to ensure that the DHCP Server module is present on the system: #Requires –Modules DhcpServer. This would have saved some code, instead of using an if statement to see if the module is present.
- The passwords could have been hardcoded, but for security reasons it is a good idea to prompt the user.
- The event did not specify that the DHCP server is running Windows Server 2012, but I think it is ok to assume that in this event so the DHCP Server module can be leveraged to query the server. A foreach loop with error handling is used to obtain the IP address for each computer.
- The information obtained from the previous foreach loop is saved to an array ($ipAddrs), which a new foreach statement is looping through in order to add the computers to the domain. Using Add-Computer is ok, but there is a gotcha not everyone thought of: The cmdlet is using WMI (the JoinDomainOrWorkgroup method of the Win32_ComputerSystem class), which is not available by default. Since the new computers is using Windows Server 2012, we can rely on PowerShell Remoting being enabled by default. One approach could then be to use Invoke-Command, and pass the Add-Computer cmdlet to Invoke-Command`s ScriptBlock parameter.
The next submission I will comment on is from Advanced 6:
- Comment based help is leveraged to provide a synopsis, description, help for all parameters, input/output type information, notes and the link to the event.
- The #requires statement is used to ensure that the PowerShell version is minimum 3.0, and that the DHCP Server module is available on the system. This is very good.
- The parameters is well defined. For the OU parameter, input validation is performed within the function. I would rather have leveraged ValidateScript for the validation, which is used for the MacAddress parameter.
- PowerShell Workflow is leveraged, but all remoting capabilities is not. Instead, the Windows Firewall is disabled in order to use the Restart-Computer cmdlet with its default protocol (DCOM). It is possible to specify WSMan as the protocol for the Restart-Computer cmdlet (-Protocol WSMan). Disabling the firewall is bad in terms of security. Note that if using PowerShell Remoting, we would also need to modify the TrustedHosts list in order to communicate with a workgroup computer. Some entries used * as the value for the TrustedHosts list. A better approach from a security standpoint would be to add the IP address for the computer we are connecting to, and to remove it after the remote commands is executed.
PS: Mike F Robbins has a very good article showing how to use PowerShell Workflow in this event.
Thank you to everyone who participated, I already look forward to the next Scripting Games. For those of you who did not participate this time, using the events as tasks for yourself (or your local PowerShell User Group) is a great learning opportunity.