2016-04-25 65 views
1

我正在使用Invoke-Command在远程服务器上执行PowerShell表达式。执行命令时出现正则表达式错误。看起来好像powershell在内部使用RegEx来分析参数,但由于某种原因,它在这种情况下失败。Powershell调用命令导致RegEx错误

特别令人困惑的是,在Invoke-Command调用中根本没有使用看起来导致解析错误的变量。我的猜测是某种变量捕获正在发生,因此可以在远程执行的脚本中引用变量(通过“使用”范围),并且这对我的$ ArtifactDirectory参数是失败的。我知道这是导致问题的$ ArtifactDirectory param,只是因为异常中“regex表达式”的值是$ ArtifactDirectory参数的值。

另一个重要的注意事项是我可以在TFS正在执行的同一台机器上手动运行脚本(使用完全相同的参数值),而不会出错。这告诉我这是某种会话选项,导致TFS构建/部署代理正在设置的问题。

下面是PowerShell脚本的相关部分:

param(
    [string] $ArtifactDirectory, 
    [string] $ComputerName 
    ) 

$someFancyCommand = "this does not seem to matter" 

Invoke-Command -ComputerName $ComputerName -ScriptBlock { 
    Invoke-Expression "$using:someFancyCommand" 
} 

这里是我如何执行它(在这种情况下,通过TFS发布管理):

MyScript.ps1 -ArtifactDirectory "C:\MSAgent\_work\66f1e4ebb\Cc - (WIP)\CC - My Cool App" -ComputerName "SomeComputer" 

这里完整的堆栈跟踪:

2016-04-25T13:53:28.6024146Z [Exception:System.Management.Automation.RuntimeException: The regular 
2016-04-25T13:53:28.6024146Z expression pattern {{C:\MSAgent\_work\66f1e4ebb\Cc - (WIP)\CC - My Cool App}} is not valid. ---> 
2016-04-25T13:53:28.6024146Z System.ArgumentException: parsing "{{C:\MSAgent\_work\66f1e4ebb\Cc - (WIP)\CC - My Cool App}}" - 
2016-04-25T13:53:28.6024146Z Unrecognized escape sequence \M. 
2016-04-25T13:53:28.6024146Z at System.Text.RegularExpressions.RegexParser.ScanCharEscape() 
2016-04-25T13:53:28.6024146Z at System.Text.RegularExpressions.RegexParser.ScanBasicBackslash() 
2016-04-25T13:53:28.6024146Z at System.Text.RegularExpressions.RegexParser.ScanRegex() 
2016-04-25T13:53:28.6024146Z at System.Text.RegularExpressions.RegexParser.Parse(String re, RegexOptions op) 
2016-04-25T13:53:28.6024146Z at System.Text.RegularExpressions.Regex..ctor(String pattern, RegexOptions options, TimeSpan matchTimeout, Boolean 
2016-04-25T13:53:28.6024146Z useCache) 
2016-04-25T13:53:28.6024146Z at System.Text.RegularExpressions.Regex..ctor(String pattern, RegexOptions options) 
2016-04-25T13:53:28.6024146Z at System.Management.Automation.ParserOps.NewRegex(String patternString, RegexOptions options) 
2016-04-25T13:53:28.6024146Z at System.Management.Automation.ParserOps.ReplaceOperator(ExecutionContext context, IScriptExtent errorPosition, 
2016-04-25T13:53:28.6226512Z Object lval, Object rval, Boolean ignoreCase) 
2016-04-25T13:53:28.6226512Z --- End of inner exception stack trace --- 
2016-04-25T13:53:28.6226512Z at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception 
2016-04-25T13:53:28.6226512Z exception) 
2016-04-25T13:53:28.6226512Z at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame) 
2016-04-25T13:53:28.6226512Z at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame) 
2016-04-25T13:53:28.6226512Z at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame) 
2016-04-25T13:53:28.6226512Z at System.Management.Automation.Interpreter.Interpreter.Run(InterpretedFrame frame) 
2016-04-25T13:53:28.6226512Z at System.Management.Automation.Interpreter.LightLambda.RunVoid1[T0](T0 arg0) 
2016-04-25T13:53:28.6336645Z at System.Management.Automation.ScriptBlock.InvokeWithPipeImpl(ScriptBlockClauseToInvoke clauseToInvoke, Boolean 
2016-04-25T13:53:28.6336645Z createLocalScope, Dictionary`2 functionsToDefine, List`1 variablesToDefine, ErrorHandlingBehavior 
2016-04-25T13:53:28.6336645Z errorHandlingBehavior, Object dollarUnder, Object input, Object scriptThis, Pipe outputPipe, InvocationInfo 
2016-04-25T13:53:28.6336645Z invocationInfo, Object[] args) 
2016-04-25T13:53:28.6336645Z at System.Management.Automation.ScriptBlock.<>c__DisplayClassa.<InvokeWithPipe>b__8() 
2016-04-25T13:53:28.6336645Z at System.Management.Automation.Runspaces.RunspaceBase.RunActionIfNoRunningPipelinesWithThreadCheck(Action action) 
2016-04-25T13:53:28.6336645Z at System.Management.Automation.ScriptBlock.InvokeWithPipe(Boolean useLocalScope, ErrorHandlingBehavior 
2016-04-25T13:53:28.6336645Z errorHandlingBehavior, Object dollarUnder, Object input, Object scriptThis, Pipe outputPipe, InvocationInfo 
2016-04-25T13:53:28.6336645Z invocationInfo, Boolean propagateAllExceptionsToTop, List`1 variablesToDefine, Dictionary`2 functionsToDefine, Object[] 
2016-04-25T13:53:28.6336645Z args) 
2016-04-25T13:53:28.6336645Z at System.Management.Automation.ScriptBlock.InvokeUsingCmdlet(Cmdlet contextCmdlet, Boolean useLocalScope, 
2016-04-25T13:53:28.6336645Z ErrorHandlingBehavior errorHandlingBehavior, Object dollarUnder, Object input, Object scriptThis, Object[] args) 
2016-04-25T13:53:28.6336645Z at Microsoft.PowerShell.Commands.ForEachObjectCommand.ProcessRecord() 
2016-04-25T13:53:28.6336645Z at System.Management.Automation.CommandProcessor.ProcessRecord()] 
+0

我想看看你如何用'$ ArtifactDirectory'生成'$ someFancyCommand'的例子吗?我想如果你真的运行了上面列表中的命令,错误是不同的。还有为什么'invoke-expression'?为什么不只是“命令”? – Matt

+0

对于$ someFancyCommand,$ ArtifactDirectory不被使用*。该$ ArtifactDirectory在Invoke-Command调用后的很长时间内在MyScript.ps1中的其他地方使用。正在执行的表达式基本上是一个TopShelf命令行来启动/停止/安装等Windows服务。表达式本身看起来像“&'c:\ myapp \ host.exe'start”。正如我在我的文章中提到的那样,命令本身似乎并不重要 - 我可以用一个简单的写主机代替它,它根本不使用变量,它仍然失败。 当你说“为什么不只是 - 命令”,你指的是什么? – RMD

+0

如果错误与'$ ArtifactDirectory'相关,那我们为什么不看它在使用中(如果错误来自PowerShell)?我假设他们是相关的,并且你只是运行一些exe文件,所以我质疑你对IEX的使用。 'Invoke-Command -Command'在这种情况下也会起作用......我又试图弄清楚变量与代码的关系。我对TFS一无所知,这可能只是我的无知。错误来自TFS发布管理吗? – Matt

回答

0

我试过了,它与普通的PowerShell一起工作。正如你在你的问题中指出的那样,这绝对是TFS Release管理问题,它是对输入参数的处理。

分辨率/工作范围:请尝试转义路径"C:\MSAgent\_work\66f1e4ebb\Cc - (WIP)\CC - My Cool App"中的所有特殊字符。 PowerShell中的转义序列是字符\

为了您的方便起见,这里的路径应该怎么看起来像转义序列:

"C:\\MSAgent\\_work\\66f1e4ebb\\Cc - \(WIP\)\\CC - My Cool App" 
1

我结束了重写整个剧本,并神奇地,错误就走开了。正如其他人指出的,尝试上述脚本的简单版本可以正常工作。事实上,它既可以通过TFS Release手动执行也可以执行。

最后,错误似乎与脚本中后面的文件复制操作有关 - 但该文件复制操作正常工作如果上述Invoke-Command调用已被删除。

所以我不知道发生了什么事,但有远程命令的执行,下面的脚本的后续执行之间的相互作用:

Get-ChildItem -Path $sourceDirectory -Recurse -Exclude $exclude | 
    Copy-Item -Destination { 
     if ($_.PSIsContainer) { 
      Join-Path $ArtifactDirectory $_.Parent.FullName.Substring($sourceDirectory.length) 
     } else { 
      Join-Path $ArtifactDirectory $_.FullName.Substring($sourceDirectory.length) 
     } 
    } -Force -Exclude $exclude -Verbose 

无论如何,我重构上述脚本转化为模块/功能,问题完全消失。