Willy’s Cave Dwelling Notes #8 – PowerShell
As part of the ALM Ranger Hands-on lab and associated environment setup, we have started using PowerShell as our setup automation framework. PowerShell consists of a CMD-like command-line shell and a scripting language, which seamlessly integrates with environments such as COM, .NET and WMI. In this post I will create a few “getting started notes”, include one of our setup scripts as an example and reference invaluable PowerShell focused material.
Getting Started
To get started you can use get-command to get a list of all the cmdlets and other elements of Windows PowerShell commands. To get additional help, type get-help and the command, followed by an optional –detailed for even more detail and samples.
Let’s peek at get-help, get-help get-command and get/set-alias commands.
- get-help command [–detailed]
- get-command
- set-alias
Creates or changes an alias for a cmdlet or other command in the current session. To save aliases use export-alias and to import the saved alias use import-alias. - get-/set execution policy
Piping
One of the brain twisters (at least for me) and a powerful feature is “piping”, which allows you to build up powerful tasks. As shown below we start with the command, followed by pipeline characters and commands, such as sort and where-object. The shown example gets all child items in the folder c:\Users\willys, sorts the list alphabetically, where the size of the object (file) is greater than 50 kilobytes.
Formatting
The pipeline and the powerful features of PowerShell allow us to do some creative formatting of the data we process.
Basic formatting, i.e. Numeric
- The same Standard Numeric Format Strings as you would use with C# or VB.NET apply.
- Example:
Basic formatting, i.e. DateTime
- Similarly the same formatting applies as you would use with C# or VB.NET apply.
- See https://technet.microsoft.com/en-us/library/ee692801 for details.
- Example:
Formatting and the Pipeline
Using a Format-Table
Select the relevant columns:
By default PowerShell shows the first four values of a property. Use $FormatEnumerationLimit to change the default.
Use –Wrap to avoid truncation:
Using a Format-List
To switch to a list view, use the Format-List:
Magic … Providers
If we call get-psprovider we find more magic in the form of Windows PowerShell providers. These present themselves as drives, allowing us to literally access environments such as WMI, environment variables and the registry like the file system, … magic.
Wish to list all hives in the registry? Simple!
Example
The following PowerShell script is one of the Hands-on lab setup scripts. It comes from the TFS Integration Tools (Platform) environment and demonstrates a number of interesting setup automation tasks:
1: #
2: # This is sample code only, do not use in production environments
3: #
4: # Copyright © Microsoft Corporation. All Rights Reserved.
5: # This code released under the terms of the
6: # Microsoft Public License (MS-PL, https://opensource.org/licenses/ms-pl.html.)
7: # This is sample code only, do not use in production environments
8: #
9:
10: function SetupHOL
11: {
12: $currentLocation = Get-Location
13: $tempLocation = Get-content env:tfspowertooldir
14:
15: if(!("C:\HOL\TFS Integration Platform\HOLSetup" -eq $currentLocation))
16: {
17: "Please run script from C:\HOL\TFS Integration Platform\HOLSetup"
18: return
19: }
20:
21: # Create logs directory if does not exist
22: if ((Test-Path -path c:\HOL\Logs\) -ne $True)
23: {
24: New-Item c:\HOL\Logs\ -type directory
25: }
26:
27: Set-Location $tempLocation
28:
29: #Create team project with tfpt
30: .\TFPT.EXE createteamproject /settingsfile:'C:\HOL\TFS Integration Platform\HOLSetup\Project_TP-A.XML'
31: .\TFPT.EXE createteamproject /settingsfile:'C:\HOL\TFS Integration Platform\HOLSetup\Project_TP-B.XML'
32: .\TFPT.EXE createteamproject /settingsfile:'C:\HOL\TFS Integration Platform\HOLSetup\Project_TP-C.XML'
33: .\TFPT.EXE createteamproject /settingsfile:'C:\HOL\TFS Integration Platform\HOLSetup\Project_RationalDemo.XML'
34:
35: $tempLocation = Get-content env:vs100comntools
36: Set-Location $tempLocation
37:
38: #Create Workspace
39: Write-Host -Object:"Create Workspace TP-A"
40: ..\IDE\TF.EXE workspace /new TP-A /noprompt /collection:https://localhost:8080/tfs/DefaultCollection
41: ..\IDE\TF.EXE workfold /map $/TP-A 'C:\HOL\TFS Integration Platform\Source Code\Demo\Sandbox-A' /workspace:TP-A
42: ..\IDE\TF.EXE workfold /unmap $/
43:
44: Write-Host -Object:"Create Workspace TP-B"
45: ..\IDE\TF.EXE workspace /new TP-B /noprompt /collection:https://localhost:8080/tfs/DefaultCollection
46: ..\IDE\TF.EXE workfold /map $/TP-B 'C:\HOL\TFS Integration Platform\Source Code\Demo\Sandbox-B' /workspace:TP-B
47: ..\IDE\TF.EXE workfold /unmap $/
48:
49: Write-Host -Object:"Create Workspace TP-C"
50: ..\IDE\TF.EXE workspace /new TP-C /noprompt /collection:https://localhost:8080/tfs/DefaultCollection
51: ..\IDE\TF.EXE workfold /map $/TP-C 'C:\HOL\TFS Integration Platform\Source Code\Demo\Sandbox-C' /workspace:TP-C
52: ..\IDE\TF.EXE workfold /unmap $/
53:
54: #Create the VC space as per HOL
55: Write-Host -Object:"Checkin code and branches"
56: ..\IDE\TF.EXE add 'C:\HOL\TFS Integration Platform\Source Code\Demo\Sandbox-A\Main' /recursive
57: ..\IDE\TF.EXE checkin 'C:\HOL\TFS Integration Platform\Source Code\Demo\Sandbox-A\Main' /comment:'HOL Automated Checkin' /recursive /noprompt
58: ..\IDE\TF.EXE branch 'C:\HOL\TFS Integration Platform\Source Code\Demo\Sandbox-A\Main’ ‘$/TP-A/Dev’
59: ..\IDE\TF.EXE checkin 'C:\HOL\TFS Integration Platform\Source Code\Demo\Sandbox-A\Dev' /comment:'HOL Automated Branch' /noprompt
60: copy 'C:\HOL\TFS Integration Platform\HOLSetup\Raw\HelloWorldDemo' 'C:\HOL\TFS Integration Platform\Source Code\Demo\Sandbox-A\Dev' -recurse
61: ..\IDE\TF.EXE add 'C:\HOL\TFS Integration Platform\Source Code\Demo\Sandbox-A\Dev\HelloWorldDemo' /recursive
62: ..\IDE\TF.EXE checkin 'C:\HOL\TFS Integration Platform\Source Code\Demo\Sandbox-A\Dev' /comment:'HOL Automated Checkin' /recursive /noprompt
63:
64: $tempLocation = Get-content env:tfspowertooldir
65: Set-Location $tempLocation
66:
67: #create workitem
68: .\TFPT.EXE workitem /new TP-A\Bug /Fields:"Title=Change the string goodbye world to hello world;Assigned To= Administrator" /collection:'https://localhost:8080/tfs/defaultcollection'
69: Set-Location $currentLocation
70: }
71:
72: #displayWelcome
73: SetupHOL
The next sample comes from the Branching Guide and shows a few different ways of dealing with some of the administrative tasks:
1: #
2: # This is sample code only, do not use in production environments
3: #
4: # Copyright © Microsoft Corporation. All Rights Reserved.
5: # This code released under the terms of the
6: # Microsoft Public License (MS-PL, https://opensource.org/licenses/ms-pl.html.)
7: # This is sample code only, do not use in production environments
8: #
9:
10: function createUser([string]$accountName, [string]$password, [string]$name)
11: {
12: # create user
13: $computer = [adsi] 'WinNT://localhost'
14: $user = $computer.Create('User', $accountName)
15: $user.SetPassword($password)
16: $user.SetInfo()
17: $user.FullName = $name
18: $user.put('UserFlags',65536 -bor 64)
19: $user.SetInfo()
20:
21: # add user to Remote desktop group to allow RD access
22: net localgroup 'Remote Desktop Users' $accountName /add
23:
24: # add user to Power Users group to allow them to logon locally
25: net localgroup 'Power Users' $accountName /add
26: }
27:
28: function createSampleAccounts
29: {
30: createUser 'michaf' 'P@ssw0rd' 'Michael Affronti (PM)'
31: createUser 'gprist' 'P@ssw0rd' 'Gary Stewart (Dev Lead)'
32: createUser 'dorikr' 'P@ssw0rd' 'Doris Krieger (Dev)'
33: createUser 'abuobe' 'P@ssw0rd' 'Abu Obeida Bakhach (Build Master)'
34: createUser 'chriko' 'P@ssw0rd' 'Christine Koch (Tester)'
35: createUser 'chriba' 'P@ssw0rd' 'Chris Barry (Business Stakeholder)'
36: createUser 'robiwo' 'P@ssw0rd' 'Robin Wood (End User)'
37: }
38:
39: function addToTFSGlobal([string]$accountName, [string]$groupname )
40: {
41: $currentLocation = Get-Location
42: $tempLocation = Get-Content env:vs100comntools
43: Set-Location $tempLocation
44:
45: ..\IDE\tfssecurity /g+ $groupname n:$accountName /server:localhost
46:
47: Set-Location $currentLocation
48: }
49:
50: function addToTFSProject([string]$accountName, [string]$groupname, [string]$collection = '', [string]$targetProjectName = '')
51: {
52: $target = ''
53: if ($targetProjectName -ne '')
54: {
55: $target = '[' +$targetProjectName + ']\' +$groupname
56: }
57: else
58: {
59: $target = $groupname
60: }
61:
62: if (!$accountName.Contains('\'))
63: {
64: $accountName = $hostname + '\' + $accountName
65: }
66:
67: $currentLocation = Get-Location
68: $tempLocation = Get-Content env:vs100comntools
69: Set-Location $tempLocation
70:
71: $argument = 'https://localhost:8080/tfs/' + $collection
72: ..\IDE\tfssecurity /g+ $target n:$accountName /collection:$argument /server:$hostname
73:
74: Set-Location $currentLocation
75: }
76:
77: function addSampleAccountsToGroups
78: {
79: addToTFSGlobal 'michaf' 'Team Foundation Administrators'
80: addToTFSGlobal 'gprist' 'Team Foundation Administrators'
81: # BuildAndDeploy
82: addToTFSProject 'michaf' 'Project Administrators' '/defaultcollection' 'BuildAndDeploy'
83: addToTFSProject 'gprist' 'Project Administrators' '/defaultcollection' 'BuildAndDeploy'
84: addToTFSProject 'dorikr' 'Contributors' '/defaultcollection' 'BuildAndDeploy'
85: addToTFSProject 'abuobe' 'Contributors' '/defaultcollection' 'BuildAndDeploy'
86: addToTFSProject 'abuobe' 'Builders' '/defaultcollection' 'BuildAndDeploy'
87: addToTFSProject 'chriko' 'Contributors' '/defaultcollection' 'BuildAndDeploy'
88: addToTFSProject 'chriba' 'Contributors' '/defaultcollection' 'BuildAndDeploy'
89: addToTFSProject 'robiwo' 'Readers' '/defaultcollection' 'BuildAndDeploy'
90: # CustomActivity
91: addToTFSProject 'michaf' 'Project Administrators' '/defaultcollection' 'CustomActivity'
92: addToTFSProject 'gprist' 'Project Administrators' '/defaultcollection' 'CustomActivity'
93: addToTFSProject 'dorikr' 'Contributors' '/defaultcollection' 'CustomActivity'
94: addToTFSProject 'abuobe' 'Contributors' '/defaultcollection' 'CustomActivity'
95: addToTFSProject 'abuobe' 'Builders' '/defaultcollection' 'CustomActivity'
96: addToTFSProject 'chriko' 'Contributors' '/defaultcollection' 'CustomActivity'
97: addToTFSProject 'chriba' 'Contributors' '/defaultcollection' 'CustomActivity'
98: addToTFSProject 'robiwo' 'Readers' '/defaultcollection' 'CustomActivity'
99: }
100:
101: function setupwebworld
102: {
103: Add-PSSnapin WebAdministration
104:
105: # Create the needed folder
106: New-Item -type directory -path "$env:systemdrive\inetpub\MVCWebs\Dev"
107: New-Item -type directory -path "$env:systemdrive\inetpub\MVCWebs\Test"
108: New-Item -type directory -path "$env:systemdrive\inetpub\MVCWebs\QA"
109:
110: # Create the needed web sites
111: New-WebSite -Name dev.contoso.com -Port 80 -HostHeader dev.contoso.com -PhysicalPath "$env:systemdrive\inetpub\MVCWebs\Dev" -ApplicationPool "ASP.NET v4.0"
112: New-WebSite -Name test.contoso.com -Port 80 -HostHeader test.contoso.com -PhysicalPath "$env:systemdrive\inetpub\MVCWebs\Test" -ApplicationPool "ASP.NET v4.0"
113: New-WebSite -Name qa.contoso.com -Port 80 -HostHeader qa.contoso.com -PhysicalPath "$env:systemdrive\inetpub\MVCWebs\QA" -ApplicationPool "ASP.NET v4.0"
114:
115: # Add host header information to the hosts file
116: Add-Content -value "127.0.0.1 dev.contoso.com" -path "C:\Windows\System32\drivers\etc\hosts"
117: Add-Content -value "127.0.0.1 test.contoso.com" -path "C:\Windows\System32\drivers\etc\hosts"
118: Add-Content -value "127.0.0.1 qa.contoso.com" -path "C:\Windows\System32\drivers\etc\hosts"
119:
120: # Disable IE phishing settings
121: # Set-Itemproperty "HKCU:\Software\Microsoft\Internet Explorer\PhishingFilter" -name Enabled -value 1
122:
123: # Disable IE Proxy properties (delete AutoConfigProxy value wininet.dll
124: Set-Itemproperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" -name ProxyEnable -value 0
125: Set-Itemproperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" -name AutoConfigProxy -value ""
126: Set-Itemproperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections" -name DefaultConnectionSettings -value ""
127:
128: # Add URL's to the local intranet zone
129: New-Item -type directory -path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\contoso.com"
130: New-Item -type directory -path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\contoso.com\dev"
131: New-Item -type directory -path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\contoso.com\test"
132: New-Item -type directory -path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\contoso.com\qa"
133: New-Itemproperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\contoso.com\dev" -name "http" -value 1 -propertytype DWord
134: New-Itemproperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\contoso.com\test" -name "http" -value 1 -propertytype DWord
135: New-Itemproperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\contoso.com\qa" -name "http" -value 1 -propertytype DWord
136: }
137:
138: function SetupHOL
139: {
140: $currentLocation = Get-Location
141: $tempLocation = Get-Content env:tfspowertooldir
142:
143: if(!("C:\HOL\BuildCustomization_ATE\HOLSetup" -eq $currentLocation))
144: {
145: "Please run script from C:\HOL\BuildCustomization_ATE\HOLSetup"
146: return
147: }
148:
149: # Create logs directory if does not exist
150: if ((Test-Path -path c:\HOL\Logs\) -ne $True)
151: {
152: New-Item c:\HOL\Logs\ -type directory
153: }
154:
155: Set-Location $tempLocation
156:
157: #Create team project with tfpt
158: .\TFPT.EXE createteamproject /settingsfile:'c:\HOL\BuildCustomization_ATE\HOLSetup\MyHOLs.XML'
159:
160: #Create team project with tfpt
161: .\TFPT.EXE createteamproject /settingsfile:'c:\HOL\BuildCustomization_ATE\HOLSetup\BuildAndDeploy.XML'
162:
163: #Create team project with tfpt
164: .\TFPT.EXE createteamproject /settingsfile:'c:\HOL\BuildCustomization_ATE\HOLSetup\CustomActivity.XML'
165:
166: #Create team project with tfpt
167: .\TFPT.EXE createteamproject /settingsfile:'C:\HOL\BuildCustomization_ATE\HOLSetup\BRDLite.XML'
168:
169: Set-Location $currentLocation
170:
171: createSampleAccounts
172: addSampleAccountsToGroups
173: setupwebworld
174: }
175:
176: SetupHOL
Upcoming fix
Mike Douglas has recently helped us troubleshoot our scripts against Windows Server 2012 and has suggested the use of the computer name instead of localhost. It seems low risk.
Existing Statement:
$computer = [adsi] 'WinNT://localhost'
Updated Statement:
$ComputerName = $env:ComputerName
$computer = [ADSI]"WinNT://$ComputerName"
Anything else we should be penciling onto our backlog?
Quick Reference Posters
Finally the posters and references.
Two posters we created a long time ago for the South-African community are hosted by the D*RP https://www.newdrp.com.
Other Cave Dwelling Notes:
- Willy’s Cave Dwelling Notes #1 – Cloud Computing
- Willy’s Cave Dwelling Notes #2 – Windows Azure
- Willy’s Cave Dwelling Notes #3 – C# … re-visiting some interesting features
- (Willy’s Cave Dwelling Notes #4 – Robert MacLean and co. poster and other gems)
- Willy’s Cave Dwelling Notes #5 – C# and Asynchronous Programming
- Willy’s Cave Dwelling Notes #6 – LINQ (Language Integrated Query)
- Willy’s Cave Dwelling Notes #7 – Doing technical demos (Snippets, etc.)