I am using a batch script for getting the latest version of specific projects. This script only runs tf.exe and gets the latest version of some Binaries. Everything works fine, but I would like to change the attrib of the downloaded files to be writeable (by deafult these files are read-only). For that I want to determine the local path of the files and use the attrib-command from batch.
tf.exe workfold [Workspace] shows me the local path in some kind of listing but it would be easier, if it only shows me what I want so I can use the prompt. Until now the it looks like this:
tf.exe workfold [Workspace]
=======================================
Arbeitsbereich: XYZ-xxxxxx (Username)
Auflistung: TFS-URL
[Workspace]: C:\xxx\TFS\xxx
Is it possible to determine only the local path mapping of a TFS Workspace so that I can use the prompt for the attrib-command without parsing?
What about the following (crude!!!) concept?
function Get-TfsWorkfold([string]$TfsCollection, [string]$TfsWorkspace)
{
$TfExePath = "${env:ProgramFiles(x86)}\Microsoft Visual Studio 10.0\Common7\IDE\TF.exe"
Write-Output "Getting workfold for '$TfsCollection'->'$TfsWorkspace'..."
Push-Location $LocalPath
& "$TfExePath" workfold /collection:$TfsCollection /workspace:$TfsWorkspace
}
function Handle-Path()
{
param([Parameter(ValueFromPipeline=$true,Position=0)] [string] $line)
$startIndex = $line.IndexOf(': ') + 2;
$correctedLine = $line.subString($startIndex, $line.length - $startIndex - 1);
Write-Output $correctedLine;
Get-ChildItem $correctedLine
}
Get-TfsWorkfold "{serverAndcollection}" "{workspace}" > c:\temp\test.txt
Select-String c:\temp\test.txt -pattern:': ' | Select-Object Line | Handle-Path
The last line in Handle-Path is the example which you can rewirte with whatever you want to. It is PowerShell but it should work as you want.
Replace {serverAndcollection} and {workspace}.
Real men do it in one line
powershell -command "& {tf workfold | Select-String -pattern:' $' -SimpleMatch | Select-Object Line | ForEach-Object {$startIndex = $_.Line.IndexOf(': ') + 2; $_.Line.subString($startIndex, $_.Line.length - $startIndex - 1)}}"
Current answer will only return one last path if there are many.
You can also do it without any string manipulation, with calls to TF.exe. I have wrapped that in PowerShell scripts, so you get the following:
function Add-TfsTypes
{
# NOTE: Not all of the below are needed, but these are all the assemblies we load at the moment. Please note that especially NewtonSoft dll MUST be loaded first!
$PathToAssemblies = "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer"
Add-Type -Path "$PathToAssemblies\NewtonSoft.Json.dll"
Add-Type -Path "$PathToAssemblies\System.Net.http.formatting.dll"
Add-Type -Path "$PathToAssemblies\Microsoft.TeamFoundation.Client.dll"
Add-Type -Path "$PathToAssemblies\Microsoft.TeamFoundation.Common.dll"
Add-Type -Path "$PathToAssemblies\Microsoft.TeamFoundation.VersionControl.Client.dll"
Add-Type -Path "$PathToAssemblies\Microsoft.TeamFoundation.WorkItemTracking.Client.dll"
}
function Get-TfsServerPathFromLocalPath {
param(
[parameter(Mandatory=$true)][string]$LocalPath,
[switch]$LoadTfsTypes
)
if ($LoadTfsTypes) {
Add-TfsTypes # Loads dlls
}
$workspaceInfo = [Microsoft.TeamFoundation.VersionControl.Client.Workstation]::Current.GetLocalWorkspaceInfo($LocalPath)
$server = New-Object Microsoft.TeamFoundation.Client.TfsTeamProjectCollection $workspaceInfo.ServerUri
$workspace = $workspaceInfo.GetWorkspace($server)
return $workspace.GetServerItemForLocalItem($LocalPath)
}
The above method can then be called like this:
$serverFolderPath = Get-TfsServerPathFromLocalPath $folderPath -LoadTfsTypes
$anotherServerPath = Get-TfsServerPathFromLocalPath $anotherItemToTestPathOn
Related
I found this script for finding where msbuild.exe is, but it's not working. When I run it, it says "A parameter cannot be found that matches parameter name 'latest'" https://github.com/microsoft/vswhere/wiki/Find-MSBuild
Here is my script:
$path = %ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe | select-object -first 1
if ($path) {
& $path $args
}
Does anyone know what I'm doing wrong? I tried encapsulating the path in quotes, and putting it into a variable and tried using Invoke-Expression but this also did not work. In bash all I would need to do is encapsulate the command with ` and it would work.
Invoke-Expression -Command "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"
x86: The term 'x86' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
This also does not work
Try this, here I am expliclty creating a list of arguments in seperate strings.
$path = "$(${env:CommonProgramFiles(x86)})\Microsoft Visual Studio\Installer\vswhere.exe"
$args = "-latest", "-requires Microsoft.Component.MSBuild", "-find MSBuild\**\Bin\MSBuild.exe"
if ($path) {
Start-Process $path -ArgumentList $args
}
I am unable to test as i dont have Visual Studio.
This is "small" script which I wrote.
It will:
download latest recomended Nuget.exe in same directory where this PS script will be saved.
download/install "vswhere" nuget (in script directory)
will find latest "MSBuild.exe" path
$latestRecomendedUrl = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
$currentScriptDir = "$PSScriptRoot"
$nuget = Join-Path "$currentScriptDir" "nuget.exe"
if (!(Test-Path "$nuget" -pathType Leaf)) {
# download if not exists
Invoke-WebRequest "$latestRecomendedUrl" -OutFile "$nuget" | Out-Null
}
$vswhereExePartFromScriptDir = (Get-ChildItem -Path "$currentScriptDir" -Filter "vswhere.exe" -Recurse -Name)
$vswhereExe = Join-Path "$currentScriptDir" "$vswhereExePartFromScriptDir"
if ([string]::IsNullOrEmpty($vswhereExePartFromScriptDir)) {
try {
$args = "install", "-x", "-o", "$currentScriptDir", "vswhere"
&"$nuget" $args
Write-Host "Nuget was successfully downloaded."
}
finally {
$vswhereExePartFromScriptDir = (Get-ChildItem -Path "$currentScriptDir" -Filter "vswhere.exe" -Recurse -Name)
$vswhereExe = Join-Path "$currentScriptDir" "$vswhereExePartFromScriptDir"
# in my case install throws error #"nuget.exe : The requested operation cannot be performed on a file with a user-mapped section open."#
# but it download vswhere package successfully - so throw error only if it does not exist
if ([string]::IsNullOrEmpty($vswhereExePartFromScriptDir)) {
Write-Error "Failed to download 'vswhere.exe'."
}
else {
Write-Host "vswhere executable: ""$vswhereExe"""
}
}
}
else {
Write-Host "vswhere executable: ""$vswhereExe"""
}
$args = "-latest", "-products", "*", "-requires", "Microsoft.Component.MSBuild", "-find", "MSBuild\**\Bin\MSBuild.exe"
$msbuildExe = $(& "$vswhereExe" $args) | select-object -first 1
Write-Host "MSBuild exeutable: ""$msbuildExe"""
Output:
Feeds used:
https://api.nuget.org/v3/index.json
C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\
Installing package 'vswhere' to 'G:\scripts\ps'.
CACHE https://api.nuget.org/v3/registration5-gz-semver2/vswhere/index.json
Attempting to gather dependency information for package 'vswhere.3.1.1' with respect to project 'G:\scripts\ps', targeting 'Any, Version=
v0.0'
Gathering dependency information took 15 ms
Attempting to resolve dependencies for package 'vswhere.3.1.1' with DependencyBehavior 'Lowest'
Resolving dependency information took 0 ms
Resolving actions to install package 'vswhere.3.1.1'
Resolved actions to install package 'vswhere.3.1.1'
Retrieving package 'vswhere 3.1.1' from 'nuget.org'.
Adding package 'vswhere.3.1.1' to folder 'G:\scripts\ps'
WARNING: Install failed. Rolling back...
Executing nuget actions took 483 ms
nuget.exe : The requested operation cannot be performed on a file with a user-mapped section open.
At G:\scripts\ps\Get-MsBuildDir.ps1:21 char:9
+ &"$nuget" $args
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (The requested o...d section open.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
Nuget was successfully downloaded.
vswhere executable: "G:\scripts\ps\vswhere\tools\vswhere.exe"
MSBuild exeutable: "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\MSBuild.exe"
I just want to determine the working directory of a running process. In Linux you can use pwdx, but i cant find a similar tool in windows. It would be perfect to get a commandline solution.
I tried nearly every possible command for windows. wmic gwmic taskkill.. none of them is a solution for my problem.
The Get-Process command in PowerShell gives you the equivalent information (at least the path of the .exe)
>Get-Process ssms | Select -Expand Path | Split-path
C:\Program Files (x86)\Microsoft SQL Server\130\Tools\Binn\ManagementStudio
You could make this your own function, if you wanted:
Function pwdx{
param($Process)
Get-Process $Process | Select -Expand Path |Split-Path
}
C:\Users\FoxDeploy> pwdx notepad
C:\WINDOWS\system32
If you need to do this in the command line in Windows, you can find the process this way.
wmic process where "name like '%notepad%'" get ExecutablePath
ExecutablePath
C:\WINDOWS\system32\notepad.exe
If you want to receive the same information as the Process Explorer you can use a Windows Management Instrumentation query on the process.
Function Query-Process-WMI
{
param
(
[Parameter( Mandatory = $true )]
[String]
$processName
)
$process = Get-Process $processName
$processInfo = $process | ForEach-Object { Get-WmiObject Win32_Process -Filter "name = '$($_.MainModule.ModuleName)'" }
$processInfoCommandLine = $processInfo | ForEach-Object { $_.CommandLine }
return $processInfoCommandLine
}
I would like to get a list of packages of my Visual Studio solution after I ran the nuget restore command.
How can I do it from command line or Powershell (oustide Visual Studio)?
You could run following PowerShell script to list all installed packages in your solution. Please modify the $SOLUTIONROOT as your solution path.
#This will be the root folder of all your solutions - we will search all children of this folder
$SOLUTIONROOT = "D:\Visual Studio 2015 Project\SO Case Sample\PackageSource"
Function ListAllPackages ($BaseDirectory)
{
Write-Host "Starting Package List - This may take a few minutes ..."
$PACKAGECONFIGS = Get-ChildItem -Recurse -Force $BaseDirectory -ErrorAction SilentlyContinue |
Where-Object { ($_.PSIsContainer -eq $false) -and ( $_.Name -eq "packages.config")}
ForEach($PACKAGECONFIG in $PACKAGECONFIGS)
{
$path = $PACKAGECONFIG.FullName
$xml = [xml]$packages = Get-Content $path
foreach($package in $packages.packages.package)
{
Write-Host $package.id
}
}
}
ListAllPackages $SOLUTIONROOT
Write-Host "Press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
I am trying to create an Init.ps1 script for a NuGet package which adds items to a solution folder which may or may not already exist in the solution.
The script successfully adds or replaces the files in the filesystem and if there was no such solution folder, the items are successfully added to the newly created solution folder, however, if the solution folder already existed, a new solution folder named NewFolder1 (or 2 and on if that already exists) is created and no files are added to the solution.
param($installPath, $toolsPath, $package)
$solutionNode = Get-Interface $dte.Solution ([EnvDTE80.Solution2])
$solutionItemsNode = $solutionNode.FindProjectItem("FolderName")
$solutionItemsProjectItems = Get-Interface $solutionNode.ProjectItems ([EnvDTE.ProjectItems])
if (!$solutionItemsProjectItems) {
$solutionItemsNode = $solutionNode.AddSolutionFolder("FolderName")
$solutionItemsProjectItems = Get-Interface $solutionItemsNode.ProjectItems ([EnvDTE.ProjectItems])
}
$rootDir = (Get-Item $installPath).parent.parent.fullname
$deploySource = join-path $installPath '\sln\'
$deployTarget = join-path $rootDir '\FolderName\'
New-Item -ItemType Directory -Force -Path $deployTarget
ls $deploySource | foreach-object {
$targetFile = join-path $deployTarget $_.Name
Copy-Item $_.FullName $targetFile -Recurse -Force
$solutionItemsProjectItems.AddFromFile($targetFile) > $null
} > $null
I have tried various alterations such as checking $solutionItemsNode instead of $solutionItemsProjectItems (same effect), adding directly to solution instead of under solution folder (did nothing) and the following change which acts the same as the original:
$solutionItemsNode = $solution.Projects | where-object { $_.ProjectName -eq "FolderName" } | select -first 1
if (!$solutionItemsNode) {
$solutionItemsNode = $solutionNode.AddSolutionFolder("FolderName")
}
Any pointers?
Related Q&As and MSDN links:
adding-solution-level-items-in-a-nuget-package
nuget-how-to-add-files-to-solution-folder
copy-files-to-solution-folder-with-init-ps1-and-nuget
link from above answer
MSDN: envdte80.solutionfolder
When you add a solution folder to a solution it is available from the EnvDTE80.Solution2's Projects property.
So using $solutionNode.Projects seems to work. The only modification to the code you had is the use of $solutionNode.Projects instead of $solution.Projects since $solution does not exist anywhere so the result would always be $null.
$solutionItemsNode = $solutionNode.Projects | where-object { $_.ProjectName -eq "FolderName" } | select -first 1
if (!$solutionItemsNode) {
$solutionItemsNode = $solutionNode.AddSolutionFolder("FolderName")
}
The code above will not add the solution folder if it already exists.
I got this script off the technet website, but I get an error when I try to execute it on my Windows 7 machine. I am completely new to scripting, but I wonder if this was made for an older OS and needs a bit of changing for Windows 7? I'm quite sure the guy who wrote it up tested it.
I get the Windows Script Host Error as follows:
Line: 1
Char: 10
Error: Expected Identifier
Code: 800A03F2
Source: Microsoft VBScript compilation error.
Here's the script:
Function New-BackUpFolder($destinationFolder)
{
$dte = get-date
$dte = $dte.tostring() -replace "[:\s/]", "."
$backUpPath = "$destinationFolder" + $dte
$null = New-Item -path $backUpPath -itemType directory
New-Backup $dataFolder $backUpPath $backUpInterval
} #end New-BackUpFolder
Function New-Backup($dataFolder,$backUpPath,$backUpInterval)
{
"backing up $dataFolder... check $backUppath for your files"
Get-Childitem -path $dataFolder -recurse |
Where-Object { $_.LastWriteTime -ge (get-date).addDays(-$backUpInterval) } |
Foreach-Object { copy-item -path $_.FullName -destination $backUpPath -force }
} #end New-BackUp
# *** entry point to script ***
$backUpInterval = 1
$dataFolder = "C:\fso"
$destinationFolder = "C:\BU\"
New-BackupFolder $destinationFolder
that's actually Powershell and not VB script. You need to run the code inside Powershell for this to work.
This link looks pretty good for a brief introduction if you haven't done PS before.
http://www.abstrys.com/files/BeginningPowershellScripting.html