성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Roll A Lisp In C - Reading ; https...
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>PowerShell로 Visual Studio 빌드 스크립트 작성</h1> <p> 그동안 msbuild를 이용한 명령행 빌드 작업을 배치 파일로 주로 처리했는데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > MSBuild - x86/x64, .NET 2/4, debug/release 빌드에 대한 배치 처리 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/1017'>http://www.sysnet.pe.kr/2/0/1017</a> </pre> <br /> 어쨌든 빌드가 복잡해지면 한정된 DOS Batch 파일의 명령어로는 버거울 때가 있습니다. 그럴 때마다 C# 콘솔 프로그램을 만들어 기능을 대체해야 하는데 그마저도 DOS Batch 명령어로 엮으려면 배치 파일이 너무 비효율적으로 복잡해지는 문제가 있습니다.<br /> <br /> 도저히 안되겠다 싶어서... 그동안 미루기만 했던 PowerShell로 완전히 갈아타기로 마음먹었습니다. ^^ 사실, .NET Framework에 익숙하다면 약간의 수고만으로 쉽게 익힐 수 있는데도 왜 이리 시간이 걸렸는지 모르겠군요.<br /> <br /> 암튼, 다음과 같이 참고할 만한 글도 있는데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Automating a Visual Studio Build with PowerShell - Part 1 ; <a target='tab' href='http://geekswithblogs.net/dwdii/archive/2011/05/20/automating-a-visual-studio-build-with-powershell---part-1.aspx'>http://geekswithblogs.net/dwdii/archive/2011/05/20/automating-a-visual-studio-build-with-powershell---part-1.aspx</a> Part 2 - Automating a Visual Studio Build with PowerShell ; <a target='tab' href='http://geekswithblogs.net/dwdii/archive/2011/05/27/part-2-automating-a-visual-studio-build-with-powershell.aspx'>http://geekswithblogs.net/dwdii/archive/2011/05/27/part-2-automating-a-visual-studio-build-with-powershell.aspx</a> Run a script in your build process ; <a target='tab' href='https://docs.microsoft.com/en-us/azure/devops/pipelines/scripts/powershell'>https://docs.microsoft.com/en-us/azure/devops/pipelines/scripts/powershell</a> </pre> <br /> 물론 위의 글대로 해도 되지만 저는 임의로 한번 구성해보았습니다.<br /> <br /> 우선, msbuild.exe의 위치를 구해야 하는데 다음과 같이 레지스트리를 이용했습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > $netFxPath = [Microsoft.Win32.Registry]::GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework", "InstallRoot", "") $msbuildPath = [IO.Path]::Combine($netFxPath, "v4.0.30319", "msbuild.exe") </pre> <br /> 그다음 프로젝트 경로를 구해야 하는데, 이는 powershell 스크립트 파일이 있는 경로를 기준으로 구할 수 있습니다. 예를 들어, build.ps1 파일을 프로젝트 파일이 있는 경로와 동일한 폴더에 두었다면 PSScriptRoot 변수를 이용하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > $projectPath = [IO.Path]::Combine(<span style='color: blue; font-weight: bold'>$PSScriptRoot</span>, "ConsoleApplication1.csproj") </pre> <br /> 이제부터는 이전과 마찬가지로 일반적인 빌드 명령으로 구성하면 되는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > $msbuildPath $projectPath /t:rebuild /p:Platform=AnyCPU;Configuration=Release </pre> <br /> 이를 실행하는 방법은 여러가지가 있습니다. 우선, cmd.exe를 통해 호출할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > cmd.exe /C $msbuildPath $projectFilePath "/p:Platform=AnyCPU;Configuration=Release" </pre> <br /> 또는 호출 연산자(&)를 이용해 직접 실행할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <span style='color: blue; font-weight: bold'>&</span> $msbuildPath $projectFilePath "/p:Platform=Win32;Configuration=Release" </pre> <br /> 빌드에 대한 성공 여부는 이전 명령어의 결과값을 담고 있는 특수 변수인 "$?"를 이용해서 구할 수 있습니다. 그래서 빌드가 실패한 경우 이후의 단계를 진행하지 않기 위해 if문과 함께 처리할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > & $msbuildPath $projectFilePath "/p:Platform=AnyCPU;Configuration=Release" Write-Output("msbuild returns: " + $?) if ($? -eq $false) { Exit $? } </pre> <br /> 그런데, 위와 같이 하면 메시지는 "msbuild returns: False"로 출력되지만 if 문의 평가는 False가 됩니다. 왜냐하면 "$?" 변수는 마지막으로 실행한 명령의 결과로 자동 업데이트되기 때문에 Write-Output 명령어 실행 조차도 결과에 반영되기 때문입니다. (즉, Write-Output 실행이 정상적으로 되었으므로 $? 값은 true로 바뀝니다.)<br /> <br /> 따라서, Write-Output 명령어를 제거하거나 다음과 같이 약간의 코드 추가를 통해 원하는 바를 구현할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > & $msbuildPath $projectFilePath "/p:Platform=Win32;Configuration=Release" <span style='color: blue; font-weight: bold'>$buildResult = $?</span> Write-Output("msbuild returns: " + $buildResult) if ($buildResult -eq $false) { Exit $buildResult } </pre> <br /> 빌드 시간 측정도 매우 쉽게 할 수 있습니다. 스크립트 시작 지점에 이렇게 코드를 넣고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > $buildStartTime = [DateTime]::Now </pre> <br /> 빌드 끝 부분에 마무리를 하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Write-Output ("Build ended (" + ([DateTime]::Now - $buildStartTime).TotalSeconds + " seconds)") </pre> <br /> 오~~~ 엄청 쉽습니다. ^^ 나머지는 이제 여러분들의 환경에 맞게 확장하면 됩니다. 예를 들어, WebClient 객체를 이용해 빌드 성공여부를 메일로 날려주는 웹 서비스를 호출할 수도 있습니다.<br /> <br /> (<a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=853&boardid=331301885'>첨부된 파일에는 위의 스크립트를 포함한 예제 프로젝트</a>가 있습니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 그 외 간단한 팁을 하나 알려드리면.<br /> <br /> 가끔 Visual Studio에서 Console 프로그램을 개발할 때 빌드된 폴더에서 직접 명령행을 통해 실행해보는 경우가 있습니다. 예를 들어, 프로젝트가 폴더가 "c:\temp\ConsoleApplicatoin1"이라고 하면 명령행에서 실행해보기 위해 다음과 같은 단계를 거쳐야 합니다.<br /> <br /> <ol> <li>Visual Studio에서 프로젝트 노드를 마우스 우클릭으로 "Open Folder in File Explorer"를 실행</li> <li>실행된 탐색기의 주소 표시줄에서 전체 경로를 복사</li> <li>"Windows + 'R'"키를 입력하고 cmd.exe를 실행</li> <li>실행된 명령행 창에 "cd "를 입력하고 마우스 우클릭으로 복사된 경로를 붙여넣기</li> <li>응용 프로그램 실행</li> </ol> <br /> 사실 이게 은근히... ^^; 짜증나는 작업인데, PowerShell과 Visual Studio의 통합이 이런 작업을 보다 간단하게 처리해 줄 수 있습니다. 가령, 다음과 같은 내용의 powershell 스크립트 파일을 프로젝트에 추가하고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > $outputPath = [IO.Path]::Combine($PSScriptRoot, "bin", "Debug") Set-Location $outputPath ./ConsoleApplication1.exe </pre> <br /> 필요할 때마다 Visual Studio에서 해당 파일을 마우스 우클릭한 다음 "Open with PowerShell ISE" 메뉴를 선택하면,<br /> <br /> <img alt='psbuild_vs_1.png' src='/SysWebRes/bbs/psbuild_vs_1.png' /> <br /><br /> 곧바로 PowerShell ISE 통합환경이 실행되고, 그 상태에서 F5(Run)키를 누르면 PowerShell 프롬프트의 기준 폴더가 Debug 폴더로 바뀌면서 지정된 응용 프로그램이 곧바로 실행됩니다. (이후로 원할 때마다 F5키를 누르면 응용 프로그램이 실행됩니다.)<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='psbuild_vs_2.png' src='/SysWebRes/bbs/psbuild_vs_2.png' /><br /> <br /> 물론, 원한다면 PowerShell ISE 통합환경에서 스크립트도 편집하면서 지속적으로 실행 테스트를 할 수 있습니다.<br /> <br /> 그 외에 한가지 더 알아두어야 할 것이 있다면, PowerShell에서 외부 파일을 실행할 때 같은 폴더에 있는 프로그램을 실행하기 위해 이름만 입력해서는 안된다는 점입니다. 그런 경우, 다음과 같은 식으로 존재하지 않는 명령어라면서 오류가 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > PS C:\temp\ConsoleApplication1\bin\Debug> <span style='color: blue; font-weight: bold'>ConsoleApplication1.exe</span> ConsoleApplication1.exe : <span style='color: blue; font-weight: bold'>The term 'ConsoleApplication1.exe' is not recognized</span> as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. At line:1 char:1 + ConsoleApplication1.exe + ~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (ConsoleApplication1.exe:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException </pre> <br /> 의도는 정확히 알 수 없지만, 마이크로소프트는 희한하게도 여기에 유닉스적인 전통을 따릅니다. 그래서 같은 폴더에 있는 명령어를 실행할 때 "./" (또는 .\)를 함께 입력하고 실행해야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > PS C:\temp\ConsoleApplication1\bin\Debug> <span style='color: blue; font-weight: bold'>./</span>ConsoleApplication1.exe </pre> <br /> <hr style='width: 50%' /><br /> <br /> 분명한 것은, PowerShell은 기존의 DOS Batch 명령어보다 훨씬 강력합니다. 게다가 언어적으로 분류하면 동적 타입 언어이기 때문에 C# 개발자라면 나름 배우는 맛이 있습니다. ^^<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
8132
(왼쪽의 숫자를 입력해야 합니다.)