Powershell: Finding items in a Visual Studio project
In the Macaw Solutions Factory we execute a lot of PowerShell code in the context of Visual Studio, meaning that we can access the Visual Studio object model directly from our PowerShell code.
There is a great add-in for Visual Studio that provides you with a PowerShell console within Visual Studio that also allows you to access the Visual Studio object model to play with VSX (Visual Studio Extensibility). This add-in is called Power Console.
If you paste the function below in this Power Console, you can find a (selection of) project items in a specified Visual Studio project.
For example:
FindProjectItems -SolutionRelativeProjectFile 'Business.ServiceInterfaces\Business.ServiceInterfaces.csproj' -Pattern '*.asmx' | select-object RelativeFileName
returns:
RelativeFileName ----------------
Internal\AnotherSoapService.asmx
SampleSoapService.asmx
What I do is that I extend the standard Visual Studio ProjectItem objects with two fields: FileName (this is the full path to the item) and RelativeFileName (this is the path to the item relative to the project folder (line 53-55). I return a collection of Visual Studio project items, with these additional fields.
A great way of testing out this kind of code is by editing it in Visual Studio using the PowerGuiVSX add-in (which uses the unsurpassed PowerGui script editor), and copying over the code into the Power Console.
- function FindProjectItems
- {
- param
- (
- $SolutionRelativeProjectFile,
- $Pattern = '*'
- )
- function FindProjectItemsRecurse
- {
- param
- (
- $AbsolutePath,
- $RelativePath = '',
- $ProjectItem,
- $Pattern
- )
- $projItemFolder = '{6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}' # Visual Studio defined constant
- if ($ProjectItem.Kind -eq $projItemFolder)
- {
- if ($ProjectItem.ProjectItems -ne $null)
- {
- if ($RelativePath -eq '')
- {
- $relativeFolderPath = $ProjectItem.Name
- }
- else
- {
- $relativeFolderPath = Join-Path -Path $RelativePath -ChildPath $ProjectItem.Name
- }
- $ProjectItem.ProjectItems | ForEach-Object {
- FindProjectItemsRecurse -AbsolutePath $AbsolutePath -RelativePath $relativeFolderPath -ProjectItem $_ -Pattern $Pattern
- }
- }
- }
- else
- {
- if ($ProjectItem.Name -like $pattern)
- {
- if ($RelativePath -eq '')
- {
- $relativeFileName = $ProjectItem.Name
- }
- else
- {
- if ($RelativePath -eq $null) { Write-Host "Relative Path is NULL" }
- $relativeFileName = Join-Path -Path $RelativePath -ChildPath $ProjectItem.Name
- }
- $fileName = Join-Path -Path $AbsolutePath -ChildPath $relativeFileName;
- $ProjectItem |
- Add-Member -MemberType NoteProperty -Name RelativeFileName -Value $relativeFileName -PassThru |
- Add-Member -MemberType NoteProperty -Name FileName -Value $fileName -PassThru
- }
- }
- }
- $proj = $DTE.Solution.Projects.Item($SolutionRelativeProjectFile)
- $projPath = Split-Path -Path $proj.FileName -Parent
- if ($proj -eq $null) { throw "No project '$SolutionRelativeProjectFile' found in current solution" }
- $proj.ProjectItems | ForEach-Object {
- FindProjectItemsRecurse -AbsolutePath $projPath -ProjectItem $_ -Pattern $Pattern
- }
- }