source

내포된 따옴표가 있는 Powershell 호출 msbuild

factcode 2023. 9. 6. 22:23
반응형

내포된 따옴표가 있는 Powershell 호출 msbuild

Powershell과 Psake를 사용하여 비주얼 스튜디오 솔루션을 위한 패키지 및 배포를 만듭니다.msdos visual studio 명령줄을 사용하여 올바르게 작동하는 msbuild를 사용하여 데이터베이스 프로젝트를 배포하려고 합니다.

   msbuild /target:Deploy /p:UseSandboxSettings=false /p:TargetConnectionString="aConnectionWithSpacesAndSemiColons" "aDatabaseProjectPathWithSpaces"

동일한 메서드 호출로 powershell에서 호출할 때 오류가 발생합니다.

& msbuild /target:Deploy /p:UseSandboxSettings=false /p:TargetConnectionString="aConnectionWithSpacesAndSemiColons" "aDatabaseProjectPathWithSpaces"

공백 관련 - powershell - 샘플 데이터베이스 연결 문자열 Data Source=에서 이 호출을 복제하는 방법을 알 수 없습니다.\SQL2008;초기 카탈로그 = 업데이트실행;통합 보안=참;

쇼트 버전

인용문이 포함된 인수를 PowerShell의 네이티브 명령어로 전달하려면 어떻게 해야 합니까?

  • 인수 문자열에 큰따옴표 대신 작은따옴표를 사용합니다.
       "/p:Target='Data Source=(local)\SQL;Integrated Security=True'"
    /p:Target='Data Source=(local)\SQL;Integrated Security=True'

  • 인수 문자열에서 큰따옴표를 사용하는 경우 backslash-escaping을 사용합니다.
       '/p:Target=\"Data Source=(local)\SQL;Integrated Security=True\"'
    /p:Target="Data Source=(local)\SQL;Integrated Security=True"

포함된 따옴표가 매개 변수의 필수 부분이 아니라 하나의 문자열로만 처리하는 경우에는 다음을 사용할 수 있습니다.

  • 인수에 따옴표를 포함하는 대신 전체 인수 문자열을 따옴표로 묶습니다.
       '/p:Target=Data Source=(local)\SQL;Integrated Security=True'
    /p:Target=Data Source=(local)\SQL;Integrated Security=True

  • 백틱을 사용하여 모든 PowerShell 특수 문자를 탈출합니다(인라인 인수로만 수행 가능)
       /p:Target=`"Data Source=`(local`)\SQL`;Integrated Security=True`"
    아니면/p:Target=Data` Source=`(local`)\SQL`;Integrated` Security=True
    /p:Target=Data Source=(local)\SQL;Integrated Security=True


전체 명령줄 예제(두 번째 대안 사용):

PS> [string[]]$arguments = @(
  '/target:Deploy',
  '/p:UseSandboxSettings=False',
  '/p:TargetDatabase=UpdatedTargetDatabase',
  '/p:TargetConnectionString=\"Data Source=(local)\SQL;Integrate Security=True\"',
  'C:\program files\MyProjectName.dbproj'
)
PS> ./echoargs $arguments
Arg 0은 </target:전개>
Arg 1은 </p:샌드박스 설정 사용하기=Smandbox>
Arg 2는 </p:대상 데이터베이스=업데이트된 대상 데이터베이스>
Arg 3은 </p:TargetConnectionString="데이터 원본=(로컬)\"SQL;통합 보안=참">Arg 4는 <C:\program files\MyProjectName.dbproj>입니다.



롱 버전

네이티브 명령어를 호출하는 것은 사람들이 기존 cmd 시스템과 PowerShell 사이를 이동할 때 꽤 많이 발생합니다("쉼표로 매개변수 구분" gotcha ;).

여기 PowerShell(v2 및 v3)의 명령 호출 주제에 대해 알고 있는 모든 내용과 수집할 수 있는 모든 예제 및 참조 자료를 정리해 보았습니다.


1) 네이티브 명령 직접 호출

1.1) 환경 경로에 위치한 실행 파일의 경우 PowerShell cmdlet을 호출하는 것처럼 명령을 직접 호출할 수 있습니다.

PS> Get-ItemProperty echoargs.exe -Name IsReadOnly
...
IsReadOnly   : True    

PS> attrib echoargs.exe
A    R       C:\Users\Emperor XLII\EchoArgs.exe


1.2) 환경 경로를 벗어나 특정 디렉토리(현재 디렉토리 포함)에 있는 명령의 경우, 명령의 전체 경로 또는 상대 경로를 사용할 수 있습니다.이 아이디어는 오퍼레이터가 "이 파일을 호출하고 싶다"고 명시적으로 선언하도록 하는 것이지, 우연히 같은 이름을 가진 임의의 파일을 대신 실행하도록 하는 것이 아닙니다(PowerShell 보안에 대한 자세한 내용은 이 질문을 참조하십시오).경로가 필요할 때 경로를 사용하지 않으면 "항이 인식되지 않음" 오류가 발생합니다.

PS> echoargs arg
The term 'echoargs' is not recognized as the name of a cmdlet, function, script file,
 or operable program...

PS> ./echoargs arg
Arg 0 is <arg>

PS> C:\Windows\system32\attrib.exe echoargs.exe
A    R       C:\Users\Emperor XLII\EchoArgs.exe


1.3) 경로에 특수문자가 포함되어 있는 경우 오퍼레이터 또는 이스케이프 문자를 사용할 수 있습니다.예를 들어, 숫자로 시작하거나 공백이 포함된 디렉토리에 있는 실행 파일입니다.

PS> $env:Path
...;C:\tools\;...

PS> Copy-Item EchoArgs.exe C:\tools\5pecialCharacter.exe
PS> 5pecialCharacter.exe special character
Bad numeric constant: 5.

PS> & 5pecialCharacter.exe special character
Arg 0 is <special>
Arg 1 is <character>

PS> `5pecialCharacter.exe escaped` character
Arg 0 is <escaped character>


PS> C:\Users\Emperor XLII\EchoArgs.exe path with spaces
The term 'C:\Users\Emperor' is not recognized as the name of a cmdlet, function,
 script file, or operable program...

PS> & 'C:\Users\Emperor XLII\EchoArgs.exe' path with spaces
Arg 0 is <path>
Arg 1 is <with>
Arg 2 is <spaces>

PS> C:\Users\Emperor` XLII\EchoArgs.exe escaped` path with` spaces
Arg 0 is <escaped path>
Arg 1 is <with spaces>


2) 간접적으로 네이티브 명령 호출

2.1) 대화형으로 명령을 입력하는 것이 아니라 경로가 변수에 저장되어 있는 경우 호출 연산자를 사용하여 변수에 이름이 지정된 명령을 호출할 수도 있습니다.

PS> $command = 'C:\Users\Emperor XLII\EchoArgs.exe'
PS> $command arg
Unexpected token 'arg' in expression or statement.

PS> & $command arg
Arg 0 is <arg>


2.2) 명령어에 전달된 인수도 변수에 저장할 수 있습니다.변수의 인수는 개별적으로 전달하거나 배열로 전달할 수 있습니다.공백을 포함하는 변수의 경우 PowerShell은 native 명령어가 단일 인수로 볼 수 있도록 공백을 자동으로 이스케이프합니다. (호 연산자는 첫 번째 값을 명령어로 처리하고 나머지 값은 인수로 처리하므로 인수를 명령어 변수와 결합해서는 안 됩니다.

PS> $singleArg = 'single arg'
PS> $mushedCommand = "$command $singleArg"
PS> $mushedCommand
C:\Users\Emperor XLII\EchoArgs.exe single arg

PS> & $mushedCommand
The term 'C:\Users\Emperor XLII\EchoArgs.exe single arg' is not recognized as the
 name of a cmdlet, function, script file, or operable program...

PS> & $command $singleArg
Arg 0 is <single arg>

PS> $multipleArgs = 'multiple','args'
PS> & $command $multipleArgs
Arg 0 is <multiple>
Arg 1 is <args>


2.3) 배열 형식은 네이티브 명령에 대한 동적 인수 목록을 작성하는 데 특히 유용합니다.각 인수가 서로 다른 매개 변수로 인식되기 위해서는 단순히 하나의 문자열에 함께 녹이는 것이 아니라 배열 변수에 저장되는 것이 중요합니다. (공통 약자인 점 참고)$args는 PowerShell의로, 할 수 . 는 PowerShell동로된을게할다수에의게다수할easorn을tee된dtne,l는esrr,dhn;cnn 대신 다음과 같은 설명적인 이름을 사용하는 것이 좋습니다.$msbuildArgs이름 지정 충돌을 방지합니다.)

PS> $mungedArguments = 'initial argument'
PS> $mungedArguments += 'second argument'
PS> $mungedArguments += $(if( $someVariable ) { 'dynamic A' } else { 'dynamic B' })
PS> ./echoargs $mungedArguments
Arg 0 is <initial argumentsecond argumentdynamic B>

PS> $arrayArguments = @('initial argument')
PS> $arrayArguments += 'second argument'
PS> $arrayArguments += $(if( $someVariable ) { 'dynamic A' } else { 'dynamic B' })
PS> ./echoargs $arrayArguments
Arg 0 is <initial argument>
Arg 1 is <second argument>
Arg 2 is <dynamic B>


2.4) 또한 스크립트, 함수, cmdlet 등의 경우, PowerShell v2는 매개 변수 순서에 대한 걱정 없이 "스플래팅"이라는 기술을 사용하여 해시 테이블에 포함된 명명된 인수를 전송할 수 있습니다.PowerShell 개체 모델에 참여하지 않고 문자열 값만 처리할 수 있는 네이티브 명령에서는 작동하지 않습니다.

PS> $cmdletArgs = @{ Path = 'EchoArgs.exe'; Name = 'IsReadOnly' }
PS> $cmdlet = 'Get-ItemProperty'
PS> & $cmdlet $cmdletArgs     # hashtable object passed to cmdlet
Cannot find path 'C:\Users\Emperor XLII\System.Collections.Hashtable'...

PS> & $cmdlet @cmdletArgs     # hashtable values passed to cmdlet
...
IsReadOnly   : True

PS> ./echoargs @cmdletArgs
Arg 0 is <Name>
Arg 1 is <IsReadOnly>
Arg 2 is <Path>
Arg 3 is <EchoArgs.exe>


3) 복잡한 인수를 사용하여 네이티브 명령 호출

3.1) 단순 인수의 경우 네이티브 명령에 사용되는 자동 탈출이면 일반적으로 충분합니다.그러나 괄호, 달러 기호, 공백 등의 경우 parser에서 해석하지 않고 그대로 네이티브 명령으로 보내려면 PowerShell에서 사용하는 문자를 이스케이프해야 합니다.이 일은 백틱 탈출 캐릭터와 함께 할 수 있습니다.`를 단문 으로써. , 을 의 에 에 의 을

PS> ./echoargs money=$10.00
Arg 0 is <money=.00>

PS> ./echoargs money=`$10.00
Arg 0 is <money=$10.00>


PS> ./echoargs value=(spaces and parenthesis)
The term 'spaces' is not recognized as the name of a cmdlet, function, script file,
 or operable program...

PS> ./echoargs 'value=(spaces and parenthesis)'
Arg 0 is <value=(spaces and parenthesis)>


3.2) 안타깝게도, 큰따옴표를 사용하는 경우 이는 그리 간단하지 않습니다.네이티브 명령에 대한 인수 처리의 일부로, PowerShell 프로세서는 인수의 내용인 sans quotes가 네이티브 명령에 단일 값으로 전달되도록 인수의 모든 큰따옴표를 정규화하려고 시도합니다.네이티브 명령 매개 변수 처리는 구문 분석 후 별도의 단계로 발생하므로 이중 따옴표에는 일반 이스케이프가 작동하지 않으며 이스케이프된 단일 따옴표 또는 백슬래시 이스케이프된 이중 따옴표만 사용할 수 있습니다.

PS> ./echoargs value="double quotes"
Arg 0 is <value=double quotes>

PS> ./echoargs 'value="string double quotes"'
Arg 0 is <value=string>
Arg 1 is <double>
Arg 2 is <quotes>

PS> ./echoargs value=`"escaped double quotes`"
Arg 0 is <value=escaped double quotes>

PS> ./echoargs 'value=\"backslash escaped double quotes\"'
Arg 0 is <value="backslash escaped double quotes">


PS> ./echoargs value='single quotes'
Arg 0 is <value=single quotes>

PS> ./echoargs "value='string single quotes'"
Arg 0 is <value='string single quotes'>

PS> ./echoargs value=`'escaped` single` quotes`'
Arg 0 is <value='escaped single quotes'>


3.3) PowerShell v3에 새로운 stop-parsing 기호 추가--%(참조).복잡한 인수 앞에 사용하면 cmd-like 값을 제외하고 구문 분석이나 변수 확장 없이 인수를 그대로 전달합니다.

PS> ./echoargs User:"$env:UserName" "Hash"#555
Arg 0 is <User:Emperor XLII>
Arg 1 is <Hash>

PS> ./echoargs User: "$env:UserName" --% "Hash"#555
Arg 0 is <User:Emperor XLII>
Arg 1 is <Hash#555>

PS> ./echoargs --% User: "%USERNAME%" "Hash"#555
Arg 0 is <User:Emperor XLII>
Arg 1 is <Hash#555>

또한 stop-parsing 기호를 문자열로 전달하여 여러 개의 인수를 나타내는 단일 문자열을 제거하는 데 사용할 수 있습니다(비록 가장 좋은 방법은 인수를 처음부터 무닝하지 않는 것이지만).

PS> $user = 'User:"%USERNAME%"'
PS> $hash = 'Hash#' + $hashNumber
PS> $mungedArguments = $user,$hash -join ' '
PS> ./echoargs $mungedArguments
Arg 0 is <User:%USERNAME% Hash#555>

PS> ./echoargs --% $mungedArguments
Arg 0 is <$mungedArguments>

PS> ./echoargs '--%' $mungedArguments
Arg 0 is <User:Emperor XLII>
Arg 1 is <Hash#555>


4) 네이티브 명령 디버깅

PowerShell이 네이티브 명령에 전달하는 인수 디버깅에는 두 가지 주요 도구가 있습니다.

4.1) 첫 번째는 PowerShell Community Extensions의 콘솔 애플리케이션으로, 각 괄호 사이에 전달된 인수를 간단히 다시 기록합니다(위의 예 참조).

4.2) 두 번째는 PowerShell이 파이프라인을 처리하는 방법에 대한 많은 세부 정보를 보여줄 수 있는 cmdlet입니다.특히.NativeCommandParameterBinder commandtrace source 및 PowerShell에 .

PS> Trace-Command *NativeCommand* { ./echoargs value="double quotes" } -PSHost
DEBUG: NativeCommandParameterBinder : Raw argument string:  "value=double quotes"
DEBUG: NativeCommandParameterBinder : Argument 0: value=double quotes

PS> Trace-Command *NativeCommand* { ./echoargs 'value="double quotes"' } -PSHost
DEBUG: NativeCommandParameterBinder : Raw argument string:  "value="double quotes""
DEBUG: NativeCommandParameterBinder : Argument 0: value=double
DEBUG: NativeCommandParameterBinder : Argument 1: quotes

PS> Trace-Command *NativeCommand* { ./echoargs value=`"double quotes`" } -PSHost
DEBUG: NativeCommandParameterBinder : Raw argument string:  value="double quotes"
DEBUG: NativeCommandParameterBinder : Argument 0: value=double quotes

PS> Trace-Command *NativeCommand* { ./echoargs 'value=\"double quotes\"' } -PSHost
DEBUG: NativeCommandParameterBinder : Raw argument string:  "value=\"double quotes\""
DEBUG: NativeCommandParameterBinder : Argument 0: value="double quotes"


기타 리소스

기사들

문의사항

이 모든 것들은 당신이 사용한다면 훨씬 더 쉬워질 것입니다.Start-Process-ArgumentList 매개 변수가 있는 d cmdlet.저는 이것이 아직 언급되지 않았다는 것이 놀랍습니다.

예:

Start-Process -FilePath msbuild.exe -ArgumentList '/target:Deploy /p:UseSandboxSettings=false /p:TargetConnectionString="aConnectionWithSpacesAndSemiColons" "aDatabaseProjectPathWithSpaces"';

다음은 제가 좀 더 잘 사용하고 싶은 방법으로, 변수 대체가 가능한 방법입니다.

$ConnectionString = 'aConnectionWithSpacesAndSemiColons';
$DatabaseProjectPath = 'aDatabaseProjectPathWithSpaces';
$MsbuildArguments = '/target:Deploy /p:UseSandboxSettings=false /p:TargetConnectionString="{0}" "{1}"' -f $ConnectionString, $DatabaseProjectPath;
Start-Process -FilePath msbuild.exe -ArgumentList $MsbuildArguments;

전체 파라미터를 작은 따옴표로 표시합니다.

& msbuild /target:Deploy /p:UseSandboxSettings=false '/p:TargetConnectionString="aConnectionWithSpacesAndSemiColons"' "aDatabaseProjectPathWithSpaces"

견적 수준이 더 높다는 것은 PSH가 PSH의 규칙으로 내용을 처리하지 않는다는 것을 의미합니다.문자열 내의 모든 단일 따옴표는 이중으로 늘려야 합니다. PSH 단일 따옴표 문자열에서 탈출하는 유일한 유형입니다.

@Richard - 이를 테스트하면 유효한 프로젝트 파일이 제공되지 않는다는 다른 오류가 발생합니다.좀 더 자세한 예시를 보여드리기 위해 echoargs pscx helper를 통해 이 내용을 실행해 보았습니다.

  1. TargetConnectionString을 래핑하는 하나의 따옴표를 사용하여 Powershell은 연결 문자열의 각 공간을 새 줄로 평가합니다.

    & echoargs /target:Deploy /p:UseSandboxSettings=false    /p:TargetDatabase=UpdatedTargetDatabase /p:TargetConnectionString='"Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False"' "C:\program files\MyProjectName.dbproj"
    
    Arg 0 is </target:Deploy>
    Arg 1 is </p:UseSandboxSettings=false>
    Arg 2 is </p:TargetDatabase=UpdatedTargetDatabase>
    Arg 3 is </p:TargetConnectionString=Data>
    Arg 4 is <Source=(local)\SQLEXPRESS;Integrated>
    Arg 5 is <Security=True;Pooling=False>
    Arg 6 is <C:\program files\MyProjectName.dbproj>
    
  2. 백틱으로 각 파라미터를 분리하면 초기 문제 = 연결 문자열 주변에 따옴표가 없습니다.

    & echoargs /target:Deploy `
    /p:UseSandboxSettings=false `
    

    c /p:TargetConnectionString="Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False""C:\program files\MyProjectName.dbproj"

    Arg 0 is </target:Deploy>
    Arg 1 is </p:UseSandboxSettings=false>
    Arg 2 is </p:TargetDatabase=UpdatedTargetDatabase>
    Arg 3 is </p:TargetConnectionString=Data Source=(local)\SQLEXPRESS;Integrated Se
    curity=True;Pooling=False>
    Arg 4 is <C:\program files\MyProjectName.dbproj>
    
  3. 따옴표에 백틱을 추가하면 예제 1과 동일하게 동작합니다.

    & echoargs /target:Deploy `
    /p:UseSandboxSettings=false `
    /p:TargetDatabase=UpdatedTargetDatabase `
    "/p:TargetConnectionString=`"Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False"`"  `
    "C:\program files\MyProjectName.dbproj"
    
  4. @ 연산자를 사용하여 매개 변수를 분할해도 인용문은 여전히 무시됩니다.

    $args = @('/target:Deploy','/p:UseSandboxSettings=false','     /p:TargetDatabase=UpdatedTargetDatabase','/p:TargetConnectionString="Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False"','C:\program files\MyProjectName.dbproj'); $args 
    
    /target:Deploy
    /p:UseSandboxSettings=false
    /p:TargetDatabase=UpdatedTargetDatabase
    /p:TargetConnectionString="Data Source=(local)\SQLEXPRESS;Integrated           Security=True;Pooling=False"
    C:\program files\MyProjectName.dbproj
    
    & echoargs $args
    
  5. 라인 구분자를 사용하여 연결 문자열을 탈출하는 백틱 - 예제 1과 같은 결과:

    & echoargs /target:Deploy `
    /p:UseSandboxSettings=false `
    /p:TargetDatabase=UpdatedTargetDatabase `
    "/p:TargetConnectionString=`"Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False"`" `
    "C:\program files\MyProjectName.dbproj"
    

문제는 PowerShell이 견적을 명령줄 응용 프로그램에 전달할 때 견적을 회피하지 않는다는 것입니다.저는 이 사실을 직접 접했고 파워쉘이 인용문을 먹고 있다고 생각했습니다.그냥 이렇게 해주세요.

msbuild /target:Deploy /p:UseSandboxSettings=false /p:TargetDatabase=UpdatedTargetDatabase '/p:TargetConnectionString=\"Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False\"' "C:\program files\MyProjectName.dbproj"

존 F의 대답 덕분에 드디어 이 문제를 알아낼 수 있었습니다.

echoargs /target:clean`;build`;deploy /p:UseSandboxSettings=false /p:TargetConnectionString=`"Data
Source=.`;Integrated Security=True`;Pooling=False`" .\MyProj.dbproj
Arg 0 is </target:clean;build;deploy>
Arg 1 is </p:UseSandboxSettings=false>
Arg 2 is </p:TargetConnectionString=Data Source=.;Integrated Security=True;Pooling=False>
Arg 3 is <.\MyProj.dbproj>

간단히 말해서, 그러나 큰따옴표와 세미콜론 앞에서 뒤로 꺾습니다.그 이하의 것(또는 그 이상의 것)은 그것을 망칠 것입니다.

답변의 문서에 나와 있지만, PowerShell 3을 사용하면 --%를 사용하여 PowerShell이 수행하는 일반적인 구문 분석을 중지할 수 있습니다.

msbuild --% /target:Deploy /p:UseSandboxSettings=false /p:TargetConnectionString="aConnectionWithSpacesAndSemiColons" "aDatabaseProjectPathWithSpaces"

언급URL : https://stackoverflow.com/questions/6224638/powershell-call-msbuild-with-nested-quotation-marks

반응형