PowerShell에서 어셈블리를로드하는 방법은 무엇입니까?


153

다음 PowerShell 코드

#Get a server object which corresponds to the default instance
$srv = New-Object -TypeName Microsoft.SqlServer.Management.SMO.Server
... rest of the script ...

다음과 같은 오류 메시지가 나타납니다.

New-Object : Cannot find type [Microsoft.SqlServer.Management.SMO.Server]: make sure 
the assembly containing this type is loaded.
At C:\Users\sortelyn\ ... \tools\sql_express_backup\backup.ps1:6  char:8
+ $srv = New-Object -TypeName Microsoft.SqlServer.Management.SMO.Server
+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidType: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand

인터넷의 모든 대답은 어셈블리를로드해야한다고 기록합니다. 오류 메시지 :-)에서 읽을 수 있는지 확인하십시오. 질문은 다음과 같습니다.

어셈블리를 어떻게로드하고 스크립트를 작동하게합니까?

답변:


179

LoadWithPartialName더 이상 사용되지 않습니다. PowerShell V3에 권장되는 솔루션은 다음과 같은 Add-Typecmdlet 을 사용하는 것입니다 .

Add-Type -Path 'C:\Program Files\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.Smo.dll'

여러 버전이 있으며 특정 버전을 선택할 수 있습니다. :-)


1
좋아, 나는 PowerShell3을 사용한다-이러한 포함 명령은 매우 복잡해 보인다. "include filename"과 같은 것을 기대합니다.
Baxter

6
PowerShell은 대소 문자를 구분하지 않습니다 (-cmatch, -ceq와 같은 연산자로 대소 문자를 구분하지 않는 한). 따라서 명령 이름과 매개 변수의 대소 문자는 중요하지 않습니다.
Keith Hill

5
예. msdn.microsoft.com/ko-kr/library/12xc5368(v=vs.110).aspx 맨 위에있는 참고 사항 참조- This API is now obsolete. 물론 사람들이 사용하지 못하게하는 것은 아닙니다.
Keith Hill

2
기술적 LoadWithPartialName으로는 더 이상 사용되지 않지만 , 그 이유 ( blogs.msdn.com/b/suzcook/archive/2003/05/30/57159.aspx에 설명 된 이유 )는 대화식 Powershell 세션에 적용되지 않습니다. 대화식 Powershell 사용에 API가 적합하다는 메모를 추가하는 것이 좋습니다.
Micha Wiedenmann

대부분의 경우 SMO 어셈블리에 문제가 없지만 때때로 Powershell을 종료해야 할 때 SMO로드 문제가 발생하기 시작합니다. add-type -Path를 추가하면 문제가 해결됩니다.
Nicolas de Fontenay 2016 년

73
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")

8
교체하지 않고 사용을 중단하기에는 너무 유용합니다! 우리 팀은 2008 및 2012 클라이언트 도구를 혼합하여 사용합니다. 이 방법은 서투른 버전 폴백 논리를 포함하지 않고 모든 팀에서 PowerShell 스크립트를 작동시키는 유일한 방법입니다.
Iain Samuel McLean Elder

4
Out-NullGAC가 물건을 에코하지 않게 하려면 출력을 파이프로 연결할 수 있습니다 .
Iain Samuel McLean Elder

3
@Baxter-이 답변 또는 Keith를 수락하고이 질문에 답변으로 표시해야합니다.
Jaykul

3
내가 사용 [무효] [System.Reflection.Assembly] :: LoadWithPartialName ( "Microsoft.SqlServer.Smo")
제작 : Soeren L. 닐슨

@IainElder "서투른 버전 폴백 로직"버전 비 호환성이 발생할 때까지 말합니다. 그렇게 말하기는 어렵지 않습니다 Add-Type -Path [...]; if (!$?) { Add-Type -Path [...] } elseif [...].
베이컨 비트

44

대부분의 사람들은 지금까지 System.Reflection.Assembly.LoadWithPartialName더 이상 사용 Add-Type -AssemblyName Microsoft.VisualBasic 되지 않는다고LoadWithPartialName 알고 있지만 다음 보다 훨씬 잘 작동하지 않는 것으로 나타났습니다 .

[Add-Type]은 시스템 컨텍스트에서 요청을 구문 분석하지 않고 "부분 이름"을 "전체 이름"으로 변환하기 위해 정적 내부 테이블을 찾습니다.

"부분 이름"이 표에 나타나지 않으면 스크립트가 실패합니다.

컴퓨터에 여러 버전의 어셈블리가 설치되어 있으면 선택할 수있는 지능형 알고리즘이 없습니다. 테이블에 나타날 것, 아마도 오래되고 오래된 것 중 하나를 얻을 것입니다.

설치 한 버전이 표에서 더 이상 사용되지 않는 버전 인 경우 스크립트가 실패합니다.

추가 유형에는와 같은 "부분 이름"에 대한 지능적인 구문 분석기가 없습니다 .LoadWithPartialNames.

Microsoft가 실제로 해야 할 일은 다음과 같습니다.

Add-Type -AssemblyName 'Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'

또는 경로를 알고 있다면 다음과 같이하십시오.

Add-Type -Path 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\Microsoft.VisualBasic\v4.0_10.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualBasic.dll'

어셈블리에 제공된 긴 이름은 강력한 이름 으로 알려져 있으며 버전과 어셈블리에 고유하며 때로는 전체 이름으로도 알려져 있습니다.

그러나 이것은 몇 가지 질문에 답하지 않습니다.

  1. 주어진 부분 이름으로 시스템에 실제로로드되는 내용의 강력한 이름을 어떻게 확인합니까?

    [System.Reflection.Assembly]::LoadWithPartialName($TypeName).Location; [System.Reflection.Assembly]::LoadWithPartialName($TypeName).FullName;

이것들은 또한 작동해야합니다 :

Add-Type -AssemblyName $TypeName -PassThru | Select-Object -ExpandProperty Assembly | Select-Object -ExpandProperty FullName -Unique
  1. 스크립트가 항상 특정 버전의 .dll을 사용하기를 원하지만 설치 위치를 확인할 수없는 경우 .dll에서 강력한 이름이 무엇인지 어떻게 알 수 있습니까?

    [System.Reflection.AssemblyName]::GetAssemblyName($Path).FullName;

또는:

Add-Type $Path -PassThru | Select-Object -ExpandProperty Assembly | Select-Object -ExpandProperty FullName -Unique
  1. 강력한 이름을 알고 있으면 .dll 경로를 어떻게 확인합니까?

    [Reflection.Assembly]::Load('Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a').Location;

  2. 그리고 비슷한 맥락에서 내가 사용하는 유형의 이름을 알고 있다면 그것이 어떤 어셈블리에서 나오는지 어떻게 알 수 있습니까?

    [Reflection.Assembly]::GetAssembly([Type]).Location [Reflection.Assembly]::GetAssembly([Type]).FullName

  3. 어떤 어셈블리를 사용할 수 있는지 어떻게 알 수 있습니까?

GAC PowerShell 모듈을 제안합니다 . Get-GacAssembly -Name 'Microsoft.SqlServer.Smo*' | Select Name, Version, FullName꽤 잘 작동합니다.

  1. Add-Type사용 하는 목록을 어떻게 볼 수 있습니까?

이것은 조금 더 복잡합니다. .Net 리플렉터를 사용하여 모든 버전의 PowerShell에서 액세스하는 방법을 설명 할 수 있습니다 (PowerShell Core 6.0의 경우 아래 업데이트 참조).

먼저, 어떤 라이브러리 Add-Type가 제공 되는지 확인하십시오 .

Get-Command -Name Add-Type | Select-Object -Property DLL

리플렉터로 결과 DLL을 엽니 다. FLOSS이기 때문에 ILSpy 를 사용 했지만 C # 리플렉터가 작동해야합니다. 해당 라이브러리를 열고에서 찾아보십시오 Microsoft.Powershell.Commands.Utility. 아래 Microsoft.Powershell.Commands에 있어야합니다 AddTypeCommand.

이를위한 코드 목록에는 개인 클래스가 InitializeStrongNameDictionary()있습니다. 여기에는 짧은 이름을 강력한 이름으로 매핑하는 사전이 나열됩니다. 내가 본 라이브러리에는 거의 750 개의 항목이 있습니다.

업데이트 : 이제 PowerShell Core 6.0이 오픈 소스입니다. 해당 버전의 경우 위의 단계를 건너 뛰고 GitHub 리포지토리에서 직접 온라인으로 코드를 볼 수 있습니다 . 그러나 해당 코드가 다른 버전의 PowerShell과 일치한다고 보장 할 수는 없습니다.


세 번째 답변되지 않은 질문 : 특정 버전이 필요하지 않은 경우 어떻게해야합니까?
jpmc26

1
@ jpmc26 글쎄, 당신은 사용할 수 있습니다 Add-Type또는 LoadWithPartialName(), 그러나 당신은 전자는 버전에 걸쳐 100 % 일치하지 않을 후자가 사용되지 않는 방법임을 알고 있어야합니다. 다시 말해, .Net은로드 한 라이브러리의 버전에 관심을 갖기를 원합니다.
베이컨 비트

@BaconBits jpmc26의 질문에 대한 완전한 대답은 PowerShell 5 또는 PowerShell 6에 있는지 여부에 따라로드 된 어셈블리가 다를 수 있다는 것입니다. JSON.NET에는 Azure PS 함수에서이 문제가 있습니다.
John Zabroski

@BaconBits 이것은 PowerShell에 대한 진정한 환상적인 심층 다이빙입니다. 책을 써야합니다.
John Zabroski

1
@KolobCanyon이 경우 일반적으로을 사용해야합니다 Add-Type -Path.이 코드는 언급 된 두 번째 코드이거나 Assembly.LoadFrom()종속성을 해결합니다 (내가 알 수있는 한 Add-Type -Path사용 방법). Assembly.LoadFile()동일하지만 경로가 다른 여러 어셈블리를로드해야하는 경우 에만 사용해야 합니다. 이상한 상황입니다.
베이컨 비트

23

PowerShell 세션 동안 어셈블리 를 잠그지 않고 어셈블리를로드 하려면 다음을 사용하십시오.

$bytes = [System.IO.File]::ReadAllBytes($storageAssemblyPath)
[System.Reflection.Assembly]::Load($bytes)

$storageAssemblyPath어셈블리의 파일 경로는 어디에 있습니까 ?

세션 내 리소스를 정리해야하는 경우 특히 유용합니다. 예를 들어 배포 스크립트에서.


1
👍 👍 👍 환상적인. Visual Studio에서 Powershell을 디버깅 할 때 PS 세션은 PowerShellToolsProcessHost를 통해 실행 후 중단됩니다. 이 접근법은 그 문제를 해결합니다. 감사.
CJBS

15

다음은 PowerShell v1, v2 및 v3에서 어셈블리를로드하는 방법에 대한 많은 예제가 포함 된 블로그 게시물입니다.

방법은 다음과 같습니다.

  • 소스 파일에서 동적으로
  • 어셈블리에서 동적으로
  • 다른 코드 타입을 사용하는 것, 즉 F #

v1.0 PowerShell 세션에서 .NET 어셈블리를로드하는 방법
v2.0 PowerShell 스크립트에서 CSharp (C #) 코드를 사용하는 방법 2.0
v3.0 Windows PowerShell에서 .NET Framework 어셈블리 사용


10

전체 * .dll 어셈블리를로드 할 수 있습니다.

$Assembly = [System.Reflection.Assembly]::LoadFrom("C:\folder\file.dll");

3

어떤 대답도 도움이되지 않아 저에게 도움이되는 솔루션을 게시하고 있습니다 .SQLPS 모듈을 가져 오는 것만으로 실수로 Restore-SqlDatabase 명령을 실행하고 작업을 시작했을 때 이것을 깨달았습니다. 그 모듈에서 어셈블리가 어떻게 든 참조되었습니다.

그냥 실행 :

Import-module SQLPS

참고 : SQLPS가 더 이상 사용되지 않는다는 점에 대해 Jason에게 감사합니다.

대신 다음을 실행하십시오.

Import-Module SqlServer

또는

Install-Module SqlServer

2
이 접근 방식을 사용하는 사람 sqlps은 모듈을 선호하여 더 이상 사용되지 않는 FYIsqlserver
Jason


2

사용할 수 있습니다 LoadWithPartialName. 그러나, 그들이 말한대로 더 이상 사용되지 않습니다.

당신은 참으로 함께 갈 수 있습니다 Add-Type, 당신은 .dll 파일의 전체 경로를 지정하지 않으려면 다른 답변 이외에, 당신은 간단하게 할 수있는 :

Add-Type -AssemblyName "Microsoft.SqlServer.Management.SMO"

나에게 이것은 SQL Server가 설치되어 있지 않기 때문에 오류를 반환했지만 (나는 추측한다), 같은 생각으로 Windows Forms 어셈블리를로드 할 수있었습니다.

Add-Type -AssemblyName "System.Windows.Forms"

MSDN 사이트에서 특정 클래스에 속하는 정확한 어셈블리 이름을 찾을 수 있습니다.

특정 클래스에 속하는 어셈블리 이름을 찾는 예


2

아래 기능이 순서대로 설치되어 있는지 확인하십시오

  1. SQL Server 용 Microsoft 시스템 CLR 유형
  2. Microsoft SQL Server 공유 관리 개체
  3. Microsoft Windows PowerShell 확장

또한 당신은로드해야 할 수도 있습니다

Add-Type -Path "C:\Program Files\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.Smo.dll"
Add-Type -Path "C:\Program Files\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.SqlWmiManagement.dll"

어셈블리를로드하는 데 일주일을 보냈고로드 한 명령문의 출력을 보지 못했지만 사용하려고 할 때 오류가 발생했습니다.이 세 가지를 설치하면 효과가있었습니다. -감사합니다
pparas

0

상단에 어셈블리 참조를 추가하십시오.

#Load the required assemblies SMO and SmoExtended.
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null

당신은 그것에서 예를 만들 수 있습니까?
endo.anaconda

1
powershell 스크립트의 시작 부분에 간단히 추가하면됩니다. 예 : 데이터베이스 백업 작성 : [System.Reflection.Assembly] :: LoadWithPartialName ( "Microsoft.SqlServer.SMO") | 널이 아닌 [System.Reflection.Assembly] :: LoadWithPartialName ( "Microsoft.SqlServer.SmoExtended") | 널이 아닌 $ SQLServer = 읽기 호스트-프롬프트 'SQL 서버 이름 (선택 사항)'IF ([string] :: IsNullOrWhitespace ($ SQLServer)) {$ SQLServer = "XXX";} $ SQLDBName = 읽기 호스트-프롬프트 ' SQL 데이터베이스 이름 (선택 사항) 'IF ([string] :: IsNullOrWhitespace ($ SQLDBName)) {$ SQLDBName = "XXX";} $ SQLLogin = 읽기 호스트
Amrita Basu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.