요즘 ADB(Android Debug Bridge)를 이용한 프로젝트를 주로 하다보니, Windows Terminal 에서 PowerShell을 많이 사용하게 되었습니다.
명령어만 치고 날려버리기 아까워서 ps1 스크립트를 작성하여 C# 프로젝트에 내장하여 사용하고자 했습니다.
PowerShell을 그동안 잘 안써왔던 저 같은 분도 계실텐데, PowerShell은 2가지가 있습니다.
Windows 10 이상에 기본적으로 설치되어 있는 Windows PowerShell 5.1 버전이 있고,
따로 설치해서 사용해야 하는 크로스플랫폼 전용 PowerShell Core 6 가 있습니다. (20240111 기준 최신 PowerShell Core는 7.4 버전입니다.)
보시면 아시겠지만 앞에 Windows가 붙었기 때문에 윈도우 전용이고 후자는 Windows 없이 Core가 붙어서 크로스플랫폼입니다.
당연하게도, Windows PowerShell은 .Net Framework를 사용하지만 PowerShell Core는 .Net Core 이상을 사용합니다.
넘버링은 .NET Framework 4.8이 .NET 5 가 되었듯 계승하여 5.1 이 6이 되었습니다.
.NET Framework 프로젝트에서는 System.Management.Automation.dll 어셈블리가 PowerShell 네임스페이스를 들고 있기에 참조해서 사용하시면 되고, .NET Standard 2.0에서는 Nuget으로 PowerShellStandard.Library 5.1.1 버전을 설치해서 사용하시면 됩니다. 그러면 안에 System.Management.Automation.dll 어셈블리가 내장되어 있습니다.
여기까지 하고나서 visual studio에서 디버깅을 하거나 빌드된 실행프로그램을 실행하면 powershell이 잘 동작합니다.
하지만 ClickOnce로 배포했을 때 문제가 발생합니다.
배포하고 ClickOnce 패키지를 설치를 하려고 하면
플랫폼 버전 정보
Windows : 10.0.19045.0 (Win32NT)
Common Language Runtime : 4.0.30319.42000
System.Deployment.dll : 4.8.9176.0 built by: NET481REL1LAST_B
clr.dll : 4.8.9181.0 built by: NET481REL1LAST_C
dfdll.dll : 4.8.9176.0 built by: NET481REL1LAST_B
dfshim.dll : 10.0.19041.30000 (WinBuild.160101.0800)
원본
배포 url : (생략!)
배포 제공자 url : (생략!)
응용 프로그램 url : (생략!)
ID
배포 ID : (생략!), Version=0.1.0.40, Culture=neutral, PublicKeyToken=d5dc1a4088bea489, processorArchitecture=amd64
응용 프로그램 ID : (생략!), Version=0.1.0.40, Culture=neutral, PublicKeyToken=d5dc1a4088bea489, processorArchitecture=amd64, type=win32
응용 프로그램 요약
* 설치 가능한 응용 프로그램입니다.
오류 요약
다음은 오류에 대한 요약입니다. 이러한 오류의 세부 정보는 나중에 로그에 기록됩니다.
* (생략!) 활성화로 예외가 발생했습니다. 다음 실패 메시지가 발견되었습니다.
+ 이 System.Management.Automation.dll 어셈블리의 강력한 이름 서명이 잘못되었습니다.
구성 요소 저장소 트랜잭션 실패 요약
트랜잭션 오류가 발생하지 않았습니다.
경고
이 작업을 수행하는 동안 경고가 발생하지 않았습니다.
작업 진행 상태
* [2024-01-11 오후 8:16:57]: (생략!) 활성화가 시작되었습니다.
* [2024-01-11 오후 8:16:57]: 배포 매니페스트의 처리가 완료되었습니다.
* [2024-01-11 오후 8:16:57]: 응용 프로그램 설치가 시작되었습니다.
* [2024-01-11 오후 8:16:57]: 응용 프로그램 매니페스트 처리가 완료되었습니다.
* [2024-01-11 오후 8:16:59]: 호환 가능한 런타임 버전 4.0.30319을(를) 찾았습니다.
* [2024-01-11 오후 8:16:59]: 트러스트 요청과 플랫폼 검색이 완료되었습니다.
오류 정보
이 작업을 수행하는 동안 다음 오류가 발생했습니다.
* [2024-01-11 오후 8:17:04] System.Deployment.Application.InvalidDeploymentException(SignatureValidation)
- 이 System.Management.Automation.dll 어셈블리의 강력한 이름 서명이 잘못되었습니다.
- 원본: System.Deployment
- 스택 추적:
위치: System.Deployment.Application.ComponentVerifier.VerifyStrongNameAssembly(String filePath, AssemblyManifest assemblyManifest)
위치: System.Deployment.Application.ComponentVerifier.VerifyComponents()
위치: System.Deployment.Application.DownloadManager.DownloadDependencies(SubscriptionState subState, AssemblyManifest deployManifest, AssemblyManifest appManifest, Uri sourceUriBase, String targetDirectory, String group, IDownloadNotification notification, DownloadOptions options)
위치: System.Deployment.Application.ApplicationActivator.DownloadApplication(SubscriptionState subState, ActivationDescription actDesc, Int64 transactionId, TempDirectory& downloadTemp)
위치: System.Deployment.Application.ApplicationActivator.InstallApplication(SubscriptionState& subState, ActivationDescription actDesc)
위치: System.Deployment.Application.ApplicationActivator.PerformDeploymentActivation(Uri activationUri, Boolean isShortcut, String textualSubId, String deploymentProviderUrlFromExtension, BrowserSettings browserSettings, String& errorPageUrl, Uri& deploymentUri)
위치: System.Deployment.Application.ApplicationActivator.PerformDeploymentActivationWithRetry(Uri activationUri, Boolean isShortcut, String textualSubId, String deploymentProviderUrlFromExtension, BrowserSettings browserSettings, String& errorPageUrl)
--- 예외가 throw된 이전 위치의 스택 추적 끝 ---
위치: System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
위치: System.Deployment.Application.ApplicationActivator.PerformDeploymentActivationWithRetry(Uri activationUri, Boolean isShortcut, String textualSubId, String deploymentProviderUrlFromExtension, BrowserSettings browserSettings, String& errorPageUrl)
위치: System.Deployment.Application.ApplicationActivator.ActivateDeploymentWorker(Object state)
이런 ClickOnce 설치 오류 메시지가 발생합니다.
문제를 찾아봤더니
이런 문서를 발견했고, 이 문서 안에
위 문서가 링크되어 있습니다.
문서를 요약하면 새로운 Visual Studio Project Template이 필요한 것이었습니다.
dotnet new -i Microsoft.PowerShell.Standard.Module.Template
를 입력하면,
이런 프로젝트 템플릿이 생성됩니다.
이 PoweShell C# 프로젝트를 Build 하면 출력되는 .NET 어셈블리를 Ipmo(Import-Module)라는 명령어로 Windows PowerShell 5.1과 PowerShell Core 6 이상에서 모두 사용할 수 있습니다.
Ipmo 명령어로 추가된 모듈은
Remove-Module -Name {모듈이름}
rmo(Remove-Module) 으로 제거할 수 있으며, 모듈명은
Get-Module
gmo(Get-Module)을 입력하여 나오는 Name 부분을 입력하면 됩니다. (확장자 없음)
추가적으로 프로젝트에서 Nuget을 확인해보니,
PowerShellStandard.Library 5.1.1이 아니라 5.1.0-preview-06 을 사용하고 있었습니다.
PowerShellStandard.Library 5.1.0-preview-06 만 설치해서 ClickOnce 배포를 해서 설치해보지는 않았습니다.
일단 이 프로젝트를 이용해서 ClickOnce 배포&설치는 성공했습니다.
더 나가실 분들은 Visual Studio PowerShell Standard Module 프로젝트 템플릿 없이 PowerShellStandard.Library 5.1.0-preview-06 이것만 설치해서 ClickOnce를 배포해보시면 될 것 같습니다.
또한, 이 Visual Studio PowerShell Standard Module 프로젝트 템플릿이던, 일반 .NET Standard Class Library 프로젝트이던, UnitTest 에서 참조해서 사용할 때는 UnitTest 프로젝트 측에서 별도로 Microsoft.PowerShell.SDK 를 종속성에 맞는 버전을 설치해서 사용했습니다.
UnitTest 프로젝트는 .NET 5 xunit 유닛테스트 프로젝트를 사용했습니다.
Microsoft.PowerShell.SDK은 종속성이 .NET 메이저 버전별로 빡쌔게 되어 있기 때문에 꼭 맞는 버전을 설치해서 사용하시면 될 것 같습니다. 상위 버전의 패키지가 하위 버전의 패키지를 전혀 지원하지 않습니다.
이상입니다.