I need to programatically extract information from a solution which contains almost 150 projects in it. The solution file is not flat though, so some of the projects are organized into folders, the folder hierarchy can be more levels deep.
This fits a recursive solution: I could write a function, which enumerates a list, and if the element is a project it would examine it, if it is a folder it would go into the folder and recursively call itself to examine the folder's content. The gist of it:
$dte = [System.Runtime.InteropServices.Marshal]::GetActiveObject("visualstudio.dte.11.0")
function traverseproject {
param([object]$prjnode, [int]$level)
if ($prjnode.Kind -eq "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}")
{
Write $prjnode.Name
Write $level
}
if ($prjnode.Kind -eq "{66A26720-8FB5-11D2-AA7E-00C04F688DDE}")
{
foreach ($prjsubnode in $prjnode)
{
traverseproject($prjsubnode, $level + 1)
}
}
}
foreach($prjn in $dte.solution.projects)
{
traverseproject($prjn, 0)
}
The problem is that the $prjnode object what the recursive function gets is weird.
Write $prjnode.Name doesn't output anything. Probably for the same reason I cannot iterate through the nodes of the folder object. Right now in the code above it's foreach ($prjsubnode in $prjnode), that just doesn't do anything silently. I tried foreach ($prjsubnode in $prjnode.ProjectItems), that gives error. I tried any kind of combinations.
From the error messages it seems that the $prjnode is type of a DTE ProjectItem link, 8E2F1269-185E-43C7-8899-950AD2769CCF. I can print out the Count property and it seems valid, but I don't see any property on the interface where I could get a hold of the contained elements. So maybe that's why I cannot iterate through? There's no way? I see the Visual Basic example at the bottom of the MSDN page I linked, but I need a working PowerShell solution.
The first call of the function seems to work OK, for example it sees the $prjnode.Kind property, but after the first recursive call things are lost.
Since you're already loading the dte, Check out http://studioshell.codeplex.com/
The feature that helps you the most:
Manage your projects, references, breakpoints, stack frame locals, menus, toolbars, Visual Studio settings, IDE windows, and even your code from PowerShell scripts, all in a consistent and discoverable way.
Here is how you can get all loaded projects with StudioShell
$projects = ls -path "DTE:\solution\Projects" -recurse
| where {$_.FileName -match ".csproj"}
Note that it may take up to 15 minutes for big solutions.
Related
I need to automate moving a solution folder with a solution. The closest I have come to be able to do this is to create a new folder and copy its contents, but then the history of those files is not preserved. I originally assumed it would be something like moving it from one ProjectItems collection to another, or maybe some sort of move method.
I see there is a command to do this:
TeamFoundationContextMenus.SourceControlExplorer.TfsContextExplorerMove
but this does not appear to be exposed (IsAvailable is false).
Not certain if it makes a difference, but I am initilizing the EnvDTE object by
$dte = [Runtime.InteropServices.Marshal]::GetActiveObject('VisualStudio.DTE')
I am writing a Windows application, which collects (possibly hundreds of) names of files, all of which live in subfolders of one particular folder (which the user can select). The list is just a subset of all the files in the folders.
I do not want to implement a user-interface that offers all kinds of sorting and selection possibilities because Windows Explorer is always much better in this regard.
Is it there an API that allows me to launch Windows Explorer from my application such that it displays my list of files as if it were the result of a search operation?
The Explorer saved search format (.search-ms) is documented on MSDN. The only downside is that it will perform the actual search when you open it, it does not contain a list of paths of files found.
If this is unacceptable then you will have to get your hands dirty deep in IShellFolder and friends.
If hosting your own window is acceptable then IExplorerBrowser will get you 99% of the way there. Call IExplorerBrowser::FillFromObject to fill the view with a custom list of files or manipulate the view directly. Example code here.
If you must display the list in Explorer then I think you will have to bite the bullet and implement a namespace extension.
You can use the SHOpenFolderAndSelectItems function to open one particular folder.
LPCWSTR pszPathToOpen = L"C:\\Users\\strives";
PIDLIST_ABSOLUTE pidl;
if (SUCCEEDED(SHParseDisplayName(pszPathToOpen, 0, &pidl, 0, 0)))
{
// we don't want to actually select anything in the folder, so we pass an empty
// PIDL in the array. if you want to select one or more items in the opened
// folder you'd need to build the PIDL array appropriately
ITEMIDLIST idNull = { 0 };
LPCITEMIDLIST pidlNull[1] = { &idNull };
SHOpenFolderAndSelectItems(pidl, 1, pidlNull, 0);
ILFree(pidl);
}
Alternatively, you can call ShellExecute on the folder directly to run its default action (which is normally to open in a browser window):
ShellExecute(NULL, NULL, "C:\\Users\\strives", NULL, NULL, SW_SHOWNORMAL);
I want to simplify Visual Studio Find in Files result, and I found a posting.
And I found it is not quite satisfactory.
Is there a way to display partial portion of directory in find result window?
ie)
x:\users\myname\project\solution_home\project1_home\src\project1.cpp
x:\users\myname\project\solution_home\project1_home\src\helper.cpp
x:\users\myname\project\solution_home\project2_home\src\helper.cpp
into
\project1_home\project1.cpp
\project1_home\helper.cpp
\project2_home\helper.cpp
IMHO, filename alone is not enough to distinguish important result, particulary in large soultion.
but, I want to eliminate certain part of directory path being repeated in every single result.
I wish there would be directory depth designation in $d format string.
ie)
$0d : file's directory
$1d : parent directory
$2d : parent of parent
... etc
Is there any extension and/or technique to do this?
PS: sorry for my poor english
I have something of a hack for this problem: map the local path to a drive. For example:
> subst Y: x:\users\myname\project\solution_home
Your Find Results will then be:
Y:\project1_home\project1.cpp
Y:\project1_home\helper.cpp
Y:\project2_home\helper.cpp
N.B. It has the side effect of breaking the CodeLens Team indicators (which must be a bug).
I'm working with csproj files, and I'm trying to write a cmdlet that extracts all of the files referenced by a project file. This will include all of the Compile, EmbeddedResource, Resource, Content, and None elements (more importantly, their #Include values) but I specifically want to exclude the Reference elements as they refer to dlls, which aren't of concern to me.
I don't have a ton of experience, but I would think the xpath expression I would want would look something like this
$projectFile | Select-Xml -namespace #{msb="http://schemas.microsoft.com/developer/msbuild/2003"} -xpath "//msb:ItemGroup/*[not(self::node() = msb:Reference) and #Include]"
However, as soon as I try to introduce the self::node() my expression returns no nodes. I'm not 100% sure that self::node() is the right way to be doing this though. Any idea what I would change to make it return, conceptually, "all Include attribute values for nodes that are not Reference elements that are child elements of an ItemGroup element?"
I think that you need:
//msb:ItemGroup/*[not(self::msb:Reference)]/#Include
Meaning: all the Include attributes of any child of msb:ItemGroup except for msb:Reference, in the whole document
I have a very complex web app project I want to re-structure. Naturally, it consists of a considerable number of folders and sub-folders. I have a huge piece of paper ready to sketch a new structure on.
Now, I need paper printouts of the projects. Some directories I need in full detail including their files - the /library directory for example that contains core parts of the engine. Other directories, I need in much less detail, with just the sub-directories, or not even that.
I am on Windows and can use the tree command but that only gives me a full listing of the whole structure I then have to clean up by hand. I would much rather have a tool which I tell which directories I need in which depth, and in which I can save those settings.
Does anybody happen to know such a tool?
Edit: I have kind of sorted it out using the tree command, deleting the entries manually. To get what I wanted I would probably have to write a script of my own, which I can't do right now. Any hints are still welcome.
I would use a bit of Powershell code for this
Take a look at this example and look at the help page for getChilItems (gci).
You can specify files to include and files not to include.
$DllFiles = gci "C:\Windows\System32" -recurse | ? {$_.extension -eq ".exe"}
Foreach ($Dll in $DllFiles) {
$Dll.name + "t " + $DLL.CreationTime + "t " + $Dll.Length
$i++
}
Write-Host The total number of files is: $i
Here is an example of the exclude parameter
Get-ChildItem c:\scripts*.* -exclude .txt,.log
there is also an include parameter is that fits your needs better.
Are you wanting a batch file/folder renamer? Or something that lets you export the tree to a CSV or XML, or do you want to just see the files you want in the tree?
I used to use a program called FileMonkey, but it hasn't been updated since 2005. A quick search for the latest and greatest batch file handler turned up a few, the one I liked is Flex Renamer.
Apoligies if you've already tried this - I have no idea of your level of Linux knowledge.
Sounds like you may want to use find. It can find everything under a certain path with
find /path/to/directory/
or it can find just directories with
find /path/to/directory/ -type d
Using either approach, you can redirect the output to a file
find /path/to/directory/ -type d >> output.txt
find /path/to/somewhere/else/ >> output.txt
and then edit the file as you see fit.
Hope that is helpful.
-Jim