programing

사용자 지정 PowerShell 모듈을 원격 세션으로 가져오는 방법은 무엇입니까?

magicmemo 2023. 8. 9. 20:39
반응형

사용자 지정 PowerShell 모듈을 원격 세션으로 가져오는 방법은 무엇입니까?

다른 컴퓨터와의 원격 세션에서 사용할 사용자 지정 PowerShell 모듈을 개발 중입니다.다음 코드(분명히 작동하지 않음)는 제가 달성하고자 하는 것을 설명합니다.

import-module .\MyCustomModule.psm1
$session = new-pssession -computerName server01
invoke-command -session $session -scriptblock { 
  <# use function defined in MyCustomModule here #> 
}

첫 번째 질문은 이 시나리오를 달성하는 것이 가능한지 여부입니다.즉, 사용자 지정 모듈을 원격 서버가 아닌 내 컴퓨터에 물리적으로 설치해야 합니다.

스레드를 찾았지만 작동하도록 관리하지 않았습니다. 원격 컴퓨터에서 로컬 컴퓨터로 세션을 다시 만들 수 없습니다.아마도, 그 스레드에 대한 댓글 중 어딘가에 언급된 구성 제한 사항에 직면했을 것입니다.게다가, 저자는 제 솔루션에 중요한 성능 영향을 언급했습니다.

그게 가능하다면 어떻게 하죠?

PowerShell 버전은 현재 제약 사항이 아닙니다. PS 3.0에서만 솔루션을 사용할 수 있다면 저는 이것을 감수할 수 있습니다.

그 질문에 대해 몇 가지 훌륭한 의견들이 있었고, 저는 그 문제에 접근하기 위한 다양한 방법들을 조사하는 데 시간을 보냈습니다.

우선, 제가 처음에 요청했던 것은 불가능합니다.제 말은, 만약 당신이 모듈의 길을 간다면, 그 모듈은 물리적으로 타겟 머신에 존재해야 합니다.Import-Module원격 세션으로 이동합니다.

제 질문을 좀 더 요약하자면, 제품 배포를 위한 재사용 가능한 PowerShell 기반 프레임워크를 만들려고 합니다.이는 푸시 방식의 배포가 될 것입니다. 즉, 로컬 시스템에서 스크립트를 실행하여 원격 서버에 배포할 것을 권장합니다.제가 그 지역을 조사한 바로는 상식적으로 우호적인 두 가지 가능한 방법이 있습니다.

모듈 접근법

따라야 할 프로세스:

  • 으로 서로 각 모듈PowerShell 모듈)에합니다.*.psm1)
  • 하고 모을원시배포확고장합다니하스를 합니다.PSModulePath location을 합니다.
  • 시스템에서 서버에 새 한 후 " " " " 를 사용합니다.Invoke-Command -Session $s -ScriptBlock {...}
  • start 스크립위치작시록블트▁in▁from▁block▁script▁start▁the위치.Import-Module CustomModule은 그은검다것니입할을 할 입니다.CustomModule 수 .

이점

이 접근 방식을 선호하는 이유는 다음과 같습니다.

  • 기존 모듈 역할의 결과 - 재사용 가능한 라이브러리 생성 촉진
  • Windows PowerShell in Action에 따르면 "모듈을 사용하여 도메인별 애플리케이션을 만들 수 있습니다."내가 알기로는 모듈 네스팅과 혼합 스크립트/바이너리 모듈을 결합하여 특정 도메인에 대한 직관적인 인터페이스를 노출함으로써 달성할 수 있습니다.기본적으로 PowerShell 기반 구축 프레임워크의 목표에 가장 중요한 요소입니다.

단점들

다음 사항을 고려하는 것이 중요합니다.

  • 사용자 지정 모듈을 원격 시스템에 전달할 방법을 찾아야 합니다.나는 NuGet을 가지고 놀았고, 그것이 그 작업에 잘 맞는지 확신할 수 없지만, MSI instra나 plain과 같은 다른 옵션들도 있습니다.xcopy공유 폴더에서.은 업그레이드 및 설치를 일반적인 보다는 내 더 .

스크립트 접근법

따라야 할 프로세스:

  • 논리적으로 서로 다른 각 기능을 별도의 PowerShell 스크립트(*.ps1)에 배치합니다.
  • 시스템에서 서버에 새 한 후 " " " " 를 사용합니다.Invoke-Command -Session $s -FilePath .\myscript.ps1합니다.
  • 다른 것을 사용합니다.Invoke-Command -Session $s -ScriptBlock {...}기능을 하십시오. 이됩니다. 이 기능은 세션에서 제공됩니다.

이점

이 접근 방식의 장점은 다음과 같습니다.

  • 모듈의 특성에 대해 알 필요가 없습니다.간단한 PowerShell 스크립트만 작성하면 됩니다.
  • 원격 시스템에 아무것도 제공할 필요가 없습니다. 이를 통해 솔루션을 더욱 단순화하고 유지보수 시 오류 발생 가능성을 낮춥니다.

단점들

물론 이상적이지는 않습니다.

  • 예를 들어 세션에 함수 집합을 "가져올" 경우 모든 함수가 "선택"되고 사용자가 볼 수 있으므로 "순환" 등이 없습니다.많은 솔루션이 이 문제를 해결할 수 있을 것이므로 이 점만을 기준으로 결정하지 마십시오.
  • 각 파일의 기능은 자체적으로 포함되어야 합니다. 여기서 도트 참조 또는 모듈 가져오기는 로컬 컴퓨터가 아닌 원격 컴퓨터를 검색합니다.

마지막으로, 원격 시스템은 여전히 원격에 대한 준비가 필요합니다.제 말은 이렇습니다.

  • 실행 정책은 기본적으로 제한되므로 다음과 같이 변경해야 합니다.Set-ExecutionPolicy Unrestricted
  • PowerShell 원격 기능을 사용하도록 설정해야 합니다.Enable-PSRemoting
  • 원격 서버의 로컬 관리자에게 추가해야 하는 대로 스크립트가 실행되는 계정
  • 원격 세션의 파일 공유에 액세스하려는 경우 멀티홉 인증에 대해 알고 있는지 확인하고 적절한 조치를 취하십시오.
  • 바이러스 백신이 친구인지 확인하고 PowerShell 지옥으로 보내지 않는지 확인합니다.

다음은 다른 방법입니다. 파일을 복사하지 않고 원격 세션에서 모듈을 다시 만듭니다.

모듈 간의 의존성에 대처하려고 시도한 적은 없지만, 단순한 자체 포함 모듈에 대해서는 문제가 없는 것 같습니다.내보내기를 쉽게 결정할 수 있도록 로컬 세션에서 사용할 수 있는 모듈에 의존하지만, 약간의 추가 작업이 있으면 모듈 파일로도 작동합니다.

function Import-ModuleRemotely([string] $moduleName,[System.Management.Automation.Runspaces.PSSession] $session)
{
    $localModule = get-module $moduleName;
    if (! $localModule) 
    { 
        write-warning "No local module by that name exists"; 
        return; 
    }
    function Exports([string] $paramName, $dictionary) 
    { 
        if ($dictionary.Keys.Count -gt 0)
        {
            $keys = $dictionary.Keys -join ",";
            return " -$paramName $keys"
        }
    }
    $fns = Exports "Function" $localModule.ExportedFunctions;
    $aliases = Exports "Alias" $localModule.ExportedAliases;
    $cmdlets = Exports "Cmdlet" $localModule.ExportedCmdlets;
    $vars = Exports "Variable" $localModule.ExportedVariables;
    $exports = "Export-ModuleMember $fns $aliases $cmdlets $vars;";

    $moduleString= @"
if (get-module $moduleName)
{
    remove-module $moduleName;
}
New-Module -name $moduleName {
$($localModule.Definition)
$exports;
}  | import-module
"@
    $script = [ScriptBlock]::Create($moduleString);
    invoke-command -session $session -scriptblock $script;
}

저는 이것이 어떠한 "해킹" 없이는 상자의 오른쪽에서 지원되지 않는다고 믿습니다.모듈을 파일 서버와 같은 공용 위치에 놓고 필요할 때 서버로 가져오는 것이 현명한 방법일 것입니다.예:

$session = new-pssession -computerName server01
invoke-command -session $session -scriptblock {
    #Set executionpolicy to bypass warnings IN THIS SESSION ONLY
    Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process
    #Import module from public location
    Import-Module \\fileserver\folders\modulelocation...


    <# use function defined in MyCustomModule here #> 
}

PS 5.0 이후로 이제 더 깨끗한 방법이 있다고 생각합니다.

Copy-Item의 ToSession 매개 변수를 사용하여 로컬 모듈을 원격 컴퓨터에 복사합니다.

여기에는 이전 솔루션의 단점이 포함되지 않습니다.

  • 미리 모듈을 원격 컴퓨터에 복사할 필요 없음
  • 공유 폴더가 없거나 모듈이 동적으로 다시 생성되지 않음:

사용 예:

$s = New-PSSession MyTargetMachine
Get-Module MyLocalModule | Import-LocalModuleToRemoteSession -Session $s -Force
# Show module is loaded
Invoke-Command $s -ScriptBlock { Get-Module }

로컬 모듈을 원격 세션으로 가져오기 기능

모듈 종속성을 로드하지 않습니다.

<#
    .SYNOPSIS
        Imports a loaded local module into a remote session
        
    .DESCRIPTION 
        This script copies a module's files loaded on the local machine to a remote session's temporary folder and imports it, before removing the temporary files.
                
        It does not require any shared folders to be exposed as it uses the default Copy-To -ToSession paramter (added in PS 5.0). 
#>
function Import-LocalModuleToRemoteSession
{
    [CmdletBinding()]
    param(
        # Module to import
        [Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName,Mandatory)]
        [System.Management.Automation.PSModuleInfo]$ModuleInfo,

        # PSSession to import module to
        [Parameter(Mandatory)]
        [System.Management.Automation.Runspaces.PSSession]
        $Session,

        # Override temporary folder location for module to be copied to on remote machine 
        [string]
        $SessionModuleFolder=$null,

        [switch]
        $Force,

        [switch]
        $SkipDeleteModuleAfterImport

    )

    begin{
        function New-TemporaryDirectory {
            $parent = [System.IO.Path]::GetTempPath()
            [string] $name = [System.Guid]::NewGuid()
            New-Item -ItemType Directory -Path (Join-Path $parent $name)
        }
    }

    process{
        
        if( [string]::IsNullOrWhiteSpace($SessionModuleFolder) ){
            Write-Verbose "Creating temporary module folder"
            $item = Invoke-Command -Session $Session -ScriptBlock ${function:New-TemporaryDirectory} -ErrorAction Stop
            $SessionModuleFolder = $item.FullName
            Write-Verbose "Created temporary folder $SessionModuleFolder"
        }

        $directory = (Join-Path -Path $SessionModuleFolder -ChildPath $ModuleInfo.Name)
        Write-Verbose "Copying module $($ModuleInfo.Name) to remote folder: $directory"
        Copy-Item `
            -ToSession $Session `
            -Recurse `
            -Path $ModuleInfo.ModuleBase `
            -Destination $directory
        
        Write-Verbose "Importing module on remote session @ $directory "

        try{
            Invoke-Command -Session $Session -ErrorAction Stop -ScriptBlock `
            { 
                Get-ChildItem (Join-Path -Path ${Using:directory} -ChildPath "*.psd1") `
                    | ForEach-Object{ 
                        Write-Debug "Importing module $_"
                        Import-Module -Name $_ #-Force:${Using:Force}
                    }
                
                    if( -not ${Using:SkipDeleteModuleAfterImport} ){
                        Write-Debug "Deleting temporary module files: $(${Using:directory})"
                        Remove-Item -Force -Recurse ${Using:directory}
                    }
            }
        }
        catch
        {
            Write-Error "Failed to import module on $Session with error: $_"
        }
    }
}

사용자 정의 기능에서 스크립트 블록을 만들어 다음을 사용하여 대상 서버로 보내는 것은 어떻습니까?Invoke-command

Import-module YourModule
$s = [scriptblock]::Create($(get-item Function:\Your-ModuleFunction).Definition)

Invoke-Command -ScriptBlock $s -Computername s1,s2,sn

이 스레드 덕분에 도움이 되었습니다.

하지만 저는 실제로 그 기능을 다시 썼습니다.

이 게시물의 원래 기능 또는 다시 작성된 기능 아래에는 모듈 매니페스트 데이터가 포함되어 있습니다.따라서 모듈의 버전 확인에 의존할 수 없습니다.

function Import-ModuleRemotely {
    Param (
        [string] $moduleName,
        [System.Management.Automation.Runspaces.PSSession] $session
    )

    Import-Module $moduleName

    $Script = @"
    if (get-module $moduleName)
    {
        remove-module $moduleName;
    }

    New-Module -Name $moduleName { $($(Get-Module $moduleName).Definition) } | Import-Module
"@

    Invoke-Command -Session $Session -ScriptBlock {
        Param($Script)
        . ([ScriptBlock]::Create($Script))
        Get-Module 
    } -ArgumentList $Script
}

언급URL : https://stackoverflow.com/questions/14441800/how-to-import-custom-powershell-module-into-the-remote-session

반응형