Как использовать Powershell для добавления/удаления ссылок на csproj?
В отношении этот предыдущий вопрос Я пытаюсь создать пакетный файл, который как часть должен удалить и добавить ссылку на файл XML *.csproj. Я просмотрел этот, этот, этот и этот предыдущий вопрос, но в качестве powershell n00b я не могу заставить его работать (пока).
Может ли кто-нибудь помочь мне со следующим? Я хочу удалить две конкретные ссылки в файле VS2010 csproj (XML) и добавить новую ссылку.
Я открыл csproj, и ссылку можно найти в следующем месте
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- ... -->
<!-- Omitted for brevity -->
<!-- ... -->
<ItemGroup Condition="'$(BuildingInsideVisualStudio)' == 'true'">
<AvailableItemName Include="Effect" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SomeDirectory\SomeProjectFile.csproj">
<Project>{AAB784E4-F8C6-4324-ABC0-6E9E0F73E575}</Project>
<Name>SomeProject</Name>
</ProjectReference>
<ProjectReference Include="..\AnotherDirectory\AnotherProjectFile.csproj">
<Project>{B0AA6A94-6784-4221-81F0-244A68C374C0}</Project>
<Name>AnotherProject</Name>
</ProjectReference>
</ItemGroup>
<!-- ... -->
<!-- Omitted for brevity -->
<!-- ... -->
</Project>
В основном я хочу:
- удалите эти две ссылки
- вставить новую ссылку на предварительно скомпилированную DLL, указанную относительным путем
- ИЛИ Добавить ссылку на сборку в проект, заданный относительным путем
В качестве очень простого примера я попробовал следующую команду powershell script, чтобы удалить все узлы ProjectReference. Я передаю путь к csproj в качестве аргумента. Я получаю ошибку Cannot validate the argument 'XML'. The Argument is null or empty
. Я могу подтвердить, что загружает csproj и сохраняет его на месте без изменений, поэтому путь правильный.
param($path)
$MsbNS = @{msb = 'http://schemas.microsoft.com/developer/msbuild/2003'}
function RemoveElement([xml]$Project, [string]$XPath, [switch]$SingleNode)
{
$xml | Select-Xml -XPath $XPath | ForEach-Object{$_.Node.ParentNode.RemoveAll()}
}
$proj = [xml](Get-Content $path)
[System.Console]::WriteLine("Loaded project {0} into {1}", $path, $proj)
RemoveElement $proj "//ProjectReference" -SingleNode
# Also tried
# RemoveElement $proj "/Project/ItemGroup/ProjectReference[@Include=`'..\SomeDirectory\SomeProjectFile.csproj`']" -SingleNode
# but complains cannot find XPath
$proj.Save($path)
Что я делаю неправильно? Любые комментарии/предложения приветствуются:)
Ответы
Ответ 1
Я думаю, проблема в том, что ваш XML файл имеет пространство имен по умолчанию xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
. Это вызывает проблемы с XPath. Итак, вы XPath //ProjectReference
вернете 0 узлов. Существует два способа решить эту проблему:
- Используйте диспетчер пространств имен.
- Использовать пространство имен agthostic XPath.
Вот как вы могли бы использовать диспетчер пространств имен:
$nsmgr = New-Object System.Xml.XmlNamespaceManager -ArgumentList $proj.NameTable
$nsmgr.AddNamespace('a','http://schemas.microsoft.com/developer/msbuild/2003')
$nodes = $proj.SelectNodes('//a:ProjectReference', $nsmgr)
Или:
Select-Xml '//a:ProjectReference' -Namespace $nsmgr
Здесь, как это сделать, используя агностик XPath пространства имен:
$nodes = $proj.SelectNodes('//*[local-name()="ProjectReference"]')
Или:
$nodes = Select-Xml '//*[local-name()="ProjectReference"]'
Второй подход может быть опасным, потому что если было несколько пространств имен, он мог бы выбрать неправильные узлы, но не ваш случай.
Ответ 2
Для потомков я дам все сценарии powershell для добавления и удаления ссылок на файлы csproj. Пожалуйста, проголосуйте за Andy Arismedi, если вы найдете этот полезный, поскольку он помог мне найти его. Не стесняйтесь давать мне +1, пока вы на нем, -)
AddReference.ps1
# Calling convension:
# AddReference.PS1 "Mycsproj.csproj",
# "MyNewDllToReference.dll",
# "MyNewDllToReference"
param([String]$path, [String]$dllRef, [String]$refName)
$proj = [xml](Get-Content $path)
[System.Console]::WriteLine("")
[System.Console]::WriteLine("AddReference {0} on {1}", $refName, $path)
# Create the following hierarchy
# <Reference Include='{0}'>
# <HintPath>{1}</HintPath>
# </Reference>
# where (0) is $refName and {1} is $dllRef
$xmlns = "http://schemas.microsoft.com/developer/msbuild/2003"
$itemGroup = $proj.CreateElement("ItemGroup", $xmlns);
$proj.Project.AppendChild($itemGroup);
$referenceNode = $proj.CreateElement("Reference", $xmlns);
$referenceNode.SetAttribute("Include", $refName);
$itemGroup.AppendChild($referenceNode)
$hintPath = $proj.CreateElement("HintPath", $xmlns);
$hintPath.InnerXml = $dllRef
$referenceNode.AppendChild($hintPath)
$proj.Save($path)
RemoveReference.ps1
# Calling Convention
# RemoveReference.ps1 "MyCsProj.csproj"
# "..\SomeDirectory\SomeProjectReferenceToRemove.dll"
param($path, $Reference)
$XPath = [string]::Format("//a:ProjectReference[@Include='{0}']", $Reference)
[System.Console]::WriteLine("");
[System.Console]::WriteLine("XPATH IS {0}", $XPath)
[System.Console]::WriteLine("");
$proj = [xml](Get-Content $path)
[System.Console]::WriteLine("Loaded project {0} into {1}", $path, $proj)
[System.Xml.XmlNamespaceManager] $nsmgr = $proj.NameTable
$nsmgr.AddNamespace('a','http://schemas.microsoft.com/developer/msbuild/2003')
$node = $proj.SelectSingleNode($XPath, $nsmgr)
if (!$node)
{
[System.Console]::WriteLine("");
[System.Console]::WriteLine("Cannot find node with XPath {0}", $XPath)
[System.Console]::WriteLine("");
exit
}
[System.Console]::WriteLine("Removing node {0}", $node)
$node.ParentNode.RemoveChild($node);
$proj.Save($path)