PSDT.VisualStudio.psm1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
<#
.Synopsis
    Imports Visual Studio command prompt variables to the current session.
.DESCRIPTION
    Check the $env:PSDT_VSCommandPromptVariable variable to see, which version of Visual Studio tools was used by the import.
#>

Function Import-VSCommandPrompt() {
    # Calls Import-VSCommandPrompt because module will be loaded.
}

$env:PSDT_VSCommandPromptVariable = $null;

Function VSCommandPrompt {
    $vsDevCmd = Get-ChildItem VsDevCmd.bat -Path "C:\*\Microsoft Visual Studio*\Common7\Tools", "C:\*\Microsoft Visual Studio\*\*\Common7\Tools" -Recurse | Select-Object -Last 1;
    $env:PSDT_VSCommandPromptVariable = $($vsDevCmd.FullName);

    Push-Location $vsDevCmd.DirectoryName;
    
    $activity = "Loading developer command prompt environment: {0}..." -f $($vsDevCmd.FullName);
    Write-Progress -Activity $activity -Status "Looking for variables...";
    
    cmd /c "$($vsDevCmd.Name)&Set" | ForEach-Object {
        if ($_ -match "=") {
            $v = $_.split("=");
            Write-Progress -Activity $activity -Status "ENV:\$($v[0]) = $($v[1])";
            Set-Item -Force -Path "ENV:\$($v[0])" -Value "$($v[1])";
        }
    }

    Write-Progress -Activity $activity -Completed;

    Pop-Location;
}

<#
.Synopsis
    Gets the Visual Studio solutions, which match the filter parameters in the current or in any child directories.
    The cmdlet's default alias is: gvss
.DESCRIPTION
    The cmdlet is using the Get-File cmdlet from the PSDT.App module, to find the solution files.
.EXAMPLE
    The example gets all solutions files on the drive R, which have a matching FullName for the pattern *common*full*.
   
    PS R:\Get-VSSolution common full
   
        Directory: R:\Source\cool-project\master\common\Sources\Builds\FullBuild

    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    -a---- 1/9/2017 8:03 AM 21870 FullBuild.sln

.EXAMPLE
    The example gets all solution files under the R:\Source, which have a matching FullName for the pattern *cool*ject*host*.

    PS R:\Source\Get-VSSolution cool ject host
    
        Directory: R:\Source\cool-project\master\accounts\Sources\Deployment\ServiceHost

    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    -a---- 1/23/2017 12:56 PM 17492 ServiceHost.sln

        Directory: R:\Source\cool-project\master\orders\Sources\Deployment\ServiceHost

    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    -a---- 3/3/2017 3:13 PM 55670 ServiceHost.sln

.EXAMPLE
    The example shows all matching projects using tab completion.

    Type the command below and press the TAB.
        
        PS R:\Get-VSSolution common full

    Pressing the tab will replace the last word with the first matching solution.
        
        PS R:\Get-VSSolution common R:\Source\cool-project\master\common\Sources\Builds\FullBuild.sln

.EXAMPLE
    The example shows all matching projects in a completion list.

    After typing the following line:
        
        PS R:\Get-VSSolution common f

    Pressing the CTRL+SPACE will replace the last word with the first matching solution's full name, and will list each other matches.
        
        PS R:\Get-VSSolution common R:\Source\cool-project\master\common\Sources\Builds\FullBuild.sln
        R:\Source\cool-project\master\common\Sources\Builds\FeedbackBuild.sln
        R:\Source\cool-project\master\common\Sources\Builds\FeatureBuild.sln

#>

Function Get-VSSolution {
    return Find-ChildItem -Filter "*.sln" @args;
}

Set-Alias gvss Get-VSSolution;

<#
.Synopsis
   Builds the specified solution.
   The cmdlet default alias is: ivsb
.DESCRIPTION
   Uses msbuild to build visual studio solution files.
.EXAMPLE
   Invoke-VSBuild -Solution Build.sln
   The example uses default values to build the explicitly passed solution.
.EXAMPLE
   Get-VSSolution Build.sln | Invoke-VSBuild
   The example uses default values to build the solution passed using pipes.
.EXAMPLE
   Invoke-VSBuild Build.sln -Target "Clean"
   The example uses the Target parameter to clean invoke the Clean msbuild target.
.EXAMPLE
   Invoke-VSBuild Build.sln -MaxCpuCount 8
   The sample uses the max cpu count property to build in parallel using 8 msbuild processes.
.EXAMPLE
   Invoke-VSBuild Build.sln -Properties "/p:SkipMerge=True" -Verbosity normal
   The samples passes a customer msbuild property using the Properties parameter and set msbuild verbosity to normal.
.EXAMPLE
   Invoke-VSBuild Build.sln -Properties "/p:Platform=x86"
   The sample uses the platform property to build e.g. a universal windows app for x86 platform.
#>

Function Invoke-VSBuild {
    [CmdletBinding()]
    Param(
        # The solution to be build.
        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
        [Alias("FullName")]
        [string]$Solution,

        # The msbuild configuration. Default is "Debug".
        [Parameter(Mandatory=$false)]
        [string]$Configuration = "Debug",

        # The msbuild target to be build. Default is "Build".
        [Parameter(Mandatory=$false)]
        [string[]]$Target = "Build",

        # The msbuild verbosity. Default is minimal.
        [Parameter(Mandatory=$false)]
        [ValidateSet('quiet','minimal','normal','detailed','diagnostics')]
        [string]$Verbosity = "minimal",

        # Additional msbuild properties like "/p:Platform=x86". The string can contain multiple properties. Use a semicolon or a comma to separate multiple properties.
        [Parameter(Mandatory=$false)]
        [string]$Properties,

        # Specifies how many cpu to use for executing msbuild. Default is 4.
        [Parameter(Mandatory=$false)]
        [string]$MaxCpuCount=4,

        # Specifiy the build output directory.
        [Parameter(Mandatory=$false)]
        [string]$OutDir
    )
    
    Process {  
        $sw = [system.diagnostics.stopwatch]::startNew();
    
        $SolutionFileInfo = Get-Item $Solution;

        $targets = $Target -join ";";
        
        $msbuild = "MSBuild.exe";
        
        $cmdlineArguments = @("$($SolutionFileInfo.FullName)", "/v:$Verbosity", "/p:Configuration=$Configuration", "/t:$targets", "/m:$MaxCpuCount");
    
        If ($Properties){$cmdlineArguments += "$Properties"}
      
        If ($OutDir){$cmdlineArguments += "/p:OutDir=$OutDir"}
        
        Write-Verbose("Commandline: $msbuild $cmdlineArguments");
    
        & $msbuild $cmdlineArguments; 
    
        $sw.Stop();
    
        Write-Host $(("Finished in {0:0.00} seconds." -f $sw.Elapsed.TotalSeconds)) -ForegroundColor Cyan
    }
}

Set-Alias ivsb Invoke-VSBuild;

<#
.Synopsis
   Executes the tests for the specified solution
   The cmdlet default alias is: ivst
.DESCRIPTION
   Uses VSTest.Console.exe to excute tests
   Assemblies containing tests are identified by default using a match on the file names. See the FileMatch parameter for default settings.
.EXAMPLE
   Invoke-VSTest -TestCaseFilter "TestCategory!=LongRunningTests"
   The example executes the tests and ignores tests marked with TestCategoryAttribute "LongRunningTests".
.EXAMPLE
   Invoke-VSTest -Parallel
   The example executes the tests in parallel.
.EXAMPLE
   Invoke-VSTest -Settings local.runsettings
   The example executes the tests using local.runsettings file.
#>

Function Invoke-VSTest {
    [CmdletBinding()]
    Param(
        # Pattern to match test files.
        # Default is set to "*tests.dll".
        [Parameter(Mandatory=$false)]
        [string]$FileMatch = "*tests.dll",

        # Pattern to match test file path.
        # Default is set to ".*\\bin\\debug\\".
        [Parameter(Mandatory=$false)]
        [string]$PathMatch = ".*\\bin\\debug\\",

        # Filter for tests. Default is set to "TestCategory!=Integrated&TestCategory!=Integration&TestCategory!=Evaluation".
        [Parameter(Mandatory=$false)]
        [string]$TestCaseFilter = "TestCategory!=Integrated&TestCategory!=Integration&TestCategory!=Evaluation",

        # Path to a runsettings file.
        [Parameter(Mandatory=$false)]
        [string]$Settings,

        # Switch to specifiy whether the tests should be excuted in parallel.
        [Switch]$Parallel
    )
    $sw = [system.diagnostics.stopwatch]::startNew();

    Write-Host "Searching for test files: Path:$PathMatch File:$FileMatch";
    
    $testAssemblies = Get-ChildItem -Filter $FileMatch -File -Recurse -ErrorAction SilentlyContinue | Where-Object {$_.FullName -match $PathMatch};
    
    Write-Host "$($testAssemblies.Length) test files found.";

    $mstest = "VSTest.Console.exe";

    $cmdlineArguments = @($testAssemblies.FullName) + @("/TestCaseFilter:`"$TestCaseFilter`"");
   
    If ($Parallel){$cmdlineArguments += "/Parallel"}

    If ($Settings){$cmdlineArguments += "/Settings:$Settings"}
    
    Write-Verbose("Commandline: $mstest $cmdlineArguments");
    
    & $mstest $cmdlineArguments; 
    
    $sw.Stop();

    Write-Host $(("Finished in {0:0.00} seconds." -f $sw.Elapsed.TotalSeconds)) -ForegroundColor Cyan
}

Set-Alias ivst Invoke-VSTest;

VSCommandPrompt;