搜索xml文件并替换其中的字符串

搜索xml文件并替换其中的字符串,xml,powershell,Xml,Powershell,我正在尝试在Windows 7中创建一个批处理文件,以帮助我删除Skype广告 以下是我到目前为止的收获: @echo off echo Editing '%WINDIR%\System32\Drivers\Etc\Hosts' file echo 127.0.0.1 apps.skype.com >> %WINDIR%\System32\Drivers\Etc\Hosts echo 127.0.0.1 g.msn.com >> %WINDIR%

我正在尝试在Windows 7中创建一个批处理文件,以帮助我删除Skype广告

以下是我到目前为止的收获:

@echo off

echo Editing '%WINDIR%\System32\Drivers\Etc\Hosts' file
echo 127.0.0.1       apps.skype.com >> %WINDIR%\System32\Drivers\Etc\Hosts
echo 127.0.0.1       g.msn.com >> %WINDIR%\System32\Drivers\Etc\Hosts

echo Editing '%APPDATA%\Skype' config
powershell -Command "(Get-ChildItem %APPDATA%\Skype -Filter "config.xml" -Recurse) | ForEach-Object { $_ -replace '<AdvertPlaceholder>1</AdvertPlaceholder>', '<AdvertPlaceholder>0</AdvertPlaceholder>' } | Set-Content $_"

ipconfig /flushdns

pause
@echo关闭
回显编辑“%WINDIR%\System32\Drivers\Etc\Hosts”文件
echo 127.0.0.1 apps.skype.com>>%WINDIR%\System32\Drivers\Etc\Hosts
echo 127.0.0.1 g.msn.com>%WINDIR%\System32\Drivers\Etc\Hosts
回显编辑“%APPDATA%\Skype”配置
powershell-Command“(Get-ChildItem%APPDATA%\Skype-Filter“config.xml”-Recurse)| ForEach对象{$\替换'1',0'}|设置内容$\
ipconfig/flushdns
暂停
powershell命令向我抛出一个错误:

Editing 'C:\Users\user\AppData\Roaming\Skype' config
Set-Content : Cannot bind argument to parameter 'Path' because it is null.
At line:1 char:218
+ (Get-ChildItem C:\Users\user\AppData\Roaming\Skype -Filter config.xml -Recurse) | ForEach-Object { $_ -replace '<AdvertPlaceholder>1</AdvertPlaceholder>
', '<AdvertPlaceholder>0</AdvertPlaceholder>' } | Set-Content <<<<  $_
    + CategoryInfo          : InvalidData: (:) [Set-Content], ParameterBinding
   ValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.SetContentCommand
编辑'C:\Users\user\AppData\Roaming\Skype'配置
Set Content:无法将参数绑定到参数“Path”,因为它为null。
第1行字符:218
+(Get ChildItem C:\Users\user\AppData\Roaming\Skype-Filter config.xml-Recurse)| ForEach对象{$\替换'1
“,“0”}设置内容>%WINDIR%\System32\Drivers\Etc\Hosts
echo 127.0.0.1 g.msn.com>%WINDIR%\System32\Drivers\Etc\Hosts
回显编辑“%APPDATA%\Skype”配置
powershell-noprofile-c“$files=Get ChildItem$env:AppData\Skype-Recurse config.xml;foreach($files中的文件){(Get Content$file.fullname)-替换“1”、“0”|设置Content$file.fullname}”
ipconfig/flushdns
回音完毕。请重新启动Skype以使更改生效。
暂停

在撰写本文时已确认工作。

您有几个问题,我认为您走错了方向<代码>设置内容接受管道输入并将其发送到文件。在大多数情况下,需要使用
-path
(或按位置)指定其路径。前面的另一个问题是,您没有实际读取找到的文件。您当前的代码正试图操纵文件名本身,这不是您想要的

与您正在寻找的内容更接近的是:

powershell -Command "$file = Get-ChildItem %APPDATA%\Skype -Filter 'config.xml' -Recurse | Select -First 1 -ExpandProperty FullName; (Get-Content $file) | ForEach-Object { $_.replace('<AdvertPlaceholder>1</AdvertPlaceholder>', '<AdvertPlaceholder>0</AdvertPlaceholder>')} | Set-Content $file"
如果您需要帮助运行脚本


我认为只有config.xml存在。如果您想编辑所有配置文件,那么几乎不需要更改。不过这次我们需要确保要编辑的值退出。因为config.xml不是唯一的名称

# Locate and read the config.xml documents. Use object notation to find the node we need to change to 0 then save the file. 
$configPaths = Get-ChildItem "$($env:appdata)\Skype" -Filter "config.xml"  -Recurse | Select-Object -ExpandProperty FullName

# Cycle each file found
$configPaths | ForEach-Object{
    $xml = [xml](Get-Content $_)
    if($xml.config.UI.General.AdvertPlaceholder){
        # Check to be sure this value actually is present before we try to change it. 
        $xml.config.UI.General.AdvertPlaceholder = "0"
        # Only need to save if change was made. 
        $xml.Save($_)
    }
}

首先,我建议在PowerShell中完成这一切,这最终简化了问题:
撇开处理两种截然不同的环境的复杂性不谈,使用
PowerShell-command
调用PowerShell命令和包含要执行的命令的命令字符串会引入引用复杂性,这可能很难解决

其次,您的问题是您的管道试图同时执行两个不同的操作:

  • 传递文件的路径
  • 同时也转换该文件的内容
您的尝试混淆了这两个任务:它传入文件对象(在字符串上下文中解析为它们的路径),然后错误地将它们视为它们的内容,然后神奇地期望修改后的内容变回文件对象(路径),告诉
设置内容
要写回哪些文件

虽然可以使用单个管道执行此操作,但实际上无法读取,因此我建议分步骤执行这两个任务:

注意:我知道您的
Get ChildItem
命令实际上只会生成一个文件,但可能会生成多个文件,因此我将尝试解决这种情况。
此外,我还避免使用
cmd.exe
变量(
%AppDate%
),而只使用PowerShell(
$env:AppData
)。
另外,请注意在下面的正则表达式中使用了反向引用(
\1
),这避免了重复
广告占位符
,也避免了在替换表达式中使用
$1
来引用正则表达式中的第一个捕获组(
广告占位符

如果我们现在只关注PowerShell,我们会得到:

$files = Get-ChildItem $env:AppData\Skype -Recurse config.xml
foreach($file in $files) { 
  (Get-Content $file.fullname) -replace '<(AdvertPlaceholder)>1</\1>', '<$1>0</$1>' |
    Set-Content $file.fullname
}

设置内容需要文件名…我最终使用了您的方法,因为您不排除任何其他config.xml文件,这与@Matt不同。虽然目前在
…\Skype\…
下的文件夹中只有一个配置文件,但如果Skype在不同的文件夹下获得更多配置文件,即使脚本不会中断。我将对此给予肯定,在编辑XML时,您的答案包含更多细节。谢谢大家!@S.T.A.L.K.E.R。如果需要,更新逻辑以允许多个文件。我只是阻止了这一点,因为我没想到会有多个skype配置文件,但很可能存在多个配置文件,并希望防止出现错误。
# Locate and read the config.xml documents. Use object notation to find the node we need to change to 0 then save the file. 
$configPaths = Get-ChildItem "$($env:appdata)\Skype" -Filter "config.xml"  -Recurse | Select-Object -ExpandProperty FullName

# Cycle each file found
$configPaths | ForEach-Object{
    $xml = [xml](Get-Content $_)
    if($xml.config.UI.General.AdvertPlaceholder){
        # Check to be sure this value actually is present before we try to change it. 
        $xml.config.UI.General.AdvertPlaceholder = "0"
        # Only need to save if change was made. 
        $xml.Save($_)
    }
}
$files = Get-ChildItem $env:AppData\Skype -Recurse config.xml
foreach($file in $files) { 
  (Get-Content $file.fullname) -replace '<(AdvertPlaceholder)>1</\1>', '<$1>0</$1>' |
    Set-Content $file.fullname
}
 powershell -noprofile -command "$files = Get-ChildItem $env:AppData\Skype -Recurse config.xml; foreach($file in $files) { (Get-Content $file.fullname) -replace '<(AdvertPlaceholder)>1</\1>', '<$1>0</$1>' | Set-Content $file.fullname }"