如何使用Powershell添加/删除对csproj的引用?

Dr.*_*ABT 12 xml powershell csproj visual-studio-2010

关于上一个问题,我试图创建一个批处理文件,作为部分必须删除并添加对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>
Run Code Online (Sandbox Code Playgroud)

基本上我想:

  • 删除这两个引用
  • 插入对相对路径指定的预编译DLL的新引用
  • 或者将程序集引用位置添加到由相对路径指定的项目中

作为一个非常简单的示例,我尝试了以下powershell脚本来删除所有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)
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?任何意见/建议欢迎:)

And*_*ndi 25

我认为问题是你的XML文件有一个默认的命名空间xmlns="http://schemas.microsoft.com/developer/msbuild/2003".这会导致XPath出现问题.所以XPath //ProjectReference将返回0个节点.有两种方法可以解决这个问题:

  1. 使用命名空间管理器.
  2. 使用名称空间不可知的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)
Run Code Online (Sandbox Code Playgroud)

要么:

Select-Xml '//a:ProjectReference' -Namespace $nsmgr
Run Code Online (Sandbox Code Playgroud)

以下是使用命名空间无关的XPath的方法:

$nodes = $proj.SelectNodes('//*[local-name()="ProjectReference"]')
Run Code Online (Sandbox Code Playgroud)

要么:

$nodes = Select-Xml '//*[local-name()="ProjectReference"]'
Run Code Online (Sandbox Code Playgroud)

第二种方法可能很危险,因为如果有多个命名空间,它可能会选择错误的节点,但不是你的情况.


Dr.*_*ABT 23

为了后人的缘故,我将提供完整的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)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

  • 只是一个FYI.而不是`[system.console] :: WriteLine`你可以使用`Write-Host` cmdlet,例如`Write-Host("这是{0}输入"-f"less")`.`-f`用于字符串格式:-) (5认同)