PowerShell の Copy-Item コマンドレットを使用して WinRM でファイル転送 リモート操作

PowerShell

前提条件

WinRM (Windows Remote Management)を有効にする

Get-Item WSMan:\localhost\Listener\*\Port 
# PowerShellを管理者として実行
Enable-PSRemoting
# 強制的に起動する場合は 
Enable-PSRemoting -Force 

※ WinRMを有効にすることで,ファイアウォールの5985番ポートがオープンします。

# ネットワークがプライベートでない場合は 
Enable-PSRemoting -SkipNetworkProfileCheck 

クライアント側で管理者権限で WinRM を起動

net start WinRM 

構成設定の状態を確認

winrm get winrm/config 

TrustedHostsを設定する

# PowerShellを管理者として (ホスト名 or IPアドレス or *)を追加 
# ホストは(private, domain)ネット上の名前、もしくはIPアドレスで設定
Set-Item WSMan:\localhost\Client\TrustedHosts -Value (ホスト名 or IPアドレス or *)
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "操作される側のIP"

WinRMでは,接続のホストから見て,接続のホストが「信頼できるホストである」ことが必要です.

接続のホストから,次のコマンドを実行

# 複数のホスト名やIPアドレスを設定する場合
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "host1, host2"
# ホストを信頼ホストリストに追加する(クライアント) 
 # 元のホストリストhost.domain,hoge.fugaにnew.hostを追加 
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "host.domain,hoge.fuga,new.host" 
# すべてのホストを信頼する場合
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*"
# 現在設定されているTrustedHostsを確認
Get-Item WSMan:\localhost\Client\TrustedHosts
# 設定されているTrustedHostsをすべて消去
Clear-Item WSMan:\localhost\Client\Trustedhosts

実装

フォルダ構成						
						
		FileCopy.				
		│  ConfigFileCopy.json				
		│  FileCopy.ps1				
		│				
		└─log				
FileCopy.ps1	

# 変数
$username   = $env:USERNAME
$hostname   = hostname
$datetime   = Get-Date -f 'yyyyMMddHHmmss'
$logdir     = "$PSScriptRoot/log/"
$logfilename   = "${username}-${hostname}-${datetime}-FileCopy.log"

# ログ記込み開始
Start-Transcript "${logdir}${logfilename}" -append

Write-Host @"
*********************************************************
*
* FileCopy Script / FileCopy.ps1
* バージョン : 
* 作成者 : 
* 作成日 : 
* 更新者 : 
* 更新日 : 
*
"@ -ForeGroundColor green

# 設定ファイルの読み込み
Write-Host "$(Get-Date -Format g) 設定ファイル読み込み : $($PSScriptRoot)/ConfigFileCopy.json"
$config = Get-Content "$PSScriptRoot/ConfigFileCopy.json" -Encoding UTF8 | ConvertFrom-Json

# TrustedHostsの確認
$arrayTrustedHosts = New-Object System.Collections.ArrayList
$TrustedHosts = $TrustedHosts = (Get-Item WSMan:\localhost\Client\TrustedHosts).Value
$TrustedHosts 
if($TrustedHosts -ne "*" ){
    # 含まれるない場合
    if(($TrustedHosts -notcontains $config.to_remote_server.remoteHost)){
        $arrayTrustedHosts.Add($TrustedHosts)
        Set-Item WSMan:\localhost\Client\TrustedHosts -Value $arrayTrustedHosts
    }
}elseif ($null -eq $TrustedHosts) {
    Set-Item WSMan:\localhost\Client\TrustedHosts -Value $TrustedHosts 
}

# パスワードを暗号化
$password = ConvertTo-SecureString $config.to_remote_server.pass -AsPlainText -Force
Write-Host "$(Get-Date -Format g) パスワードを暗号化 : " $password

# 非対話型認証作成
$Credential = New-Object System.Management.Automation.PSCredential ($config.to_remote_server.user, $password) 
Write-Host "$(Get-Date -Format g) 非対話型認証作成 : " $Credential

try{
    # PSセッションを作成
    $PSsession = New-PSSession -ComputerName $config.to_remote_server.remoteHost -Credential $Credential 
    Write-Host "$(Get-Date -Format g) PSセッションを作成 : " $PSsession

    # リモートでクライアントにあるPSを実行
    $outdir = $config.to_remote_server.to_path
    $RemoteOutdir = Invoke-Command -Session $PSsession -Scriptblock{
        if (-not (Test-Path -LiteralPath $args[0])){
            New-Item -LiteralPath $args[0]  -ItemType Directory -Force
            Write-Host "[INFO] コピー先ディレクトリ $outdir を作成しました。"
        }
    } -ArgumentList $outdir

    $RemoteOutdir

    $indir     = $config.from_server.from_path
    $filenames = $config.from_server.file_name
    if(Test-Path -LiteralPath $indir ){
        # 対象ファイを取得し、コピー先サーバーのディレクトリへコピー
        $exclude_array_name = New-Object System.Collections.Generic.List[string]
        $filelists = Get-ChildItem -LiteralPath $indir | Where-Object {$_.Name -In $filenames }
        $filelists | ForEach-Object {
            $exclude_array_name.Add($_.Name + "_*")
            $outfile = $outdir + "\" + $_.Name + "_" + $datetime
            Copy-Item -LiteralPath $_.FullName -Destination $outfile -Recurse 
            Write-Host "[INFO] $infile から $outfile をコピーしました。"
        }
    }

} catch [Exception]{
    Write-Host 'リモートPCへの接続エラー OR ファイルコピーのエラー。'
    Write-Host $Error
}

try{
    
    # コピー先のディレクトリで6世代以上保持し、最も日付が古いものは削除
    # 更新日降順にソートし、-First 指定で、先頭何個まで取得
    $exclude_array = (Get-ChildItem -LiteralPath $outdir -Include $exclude_array_name |
                        Sort-Object -Property { $_.LastWriteTime} -Descending |
                        Select-Object -First (6 * $filenames.Length)).Name
    
    Remove-Item "${outdir}\*" -Exclude $exclude_array -Recurse
    Write-Host "$(Get-Date -Format g) $exclude_array  以外ファイルを削除"

    # "${username}-${hostname}-${datetime}-FileCop.log"以外の logファイルを削除
    Remove-Item "${logdir}\*" -Exclude ${logfilename} -Recurse
    Write-Host "$(Get-Date -Format g) ${logfilename} 以外ファイルを削除"

} catch [Exception]{
    Write-Host 'ファイル削除にエラーが発生しました。'
    Write-Host $Error
}

# Write-Host "`r`n**セッション切断**" -ForeGroundColor green
Remove-PSSession $PSsession

# ログ出力終了
Stop-Transcript
ConfigFileCopy.json JSONファイル内容								
[ 
    { 
        "from_server": { 
          "from_path": "C:\\Users\\Use\\Desktop\\サーバーAディレクトリ", 
          "file_name": ["test.DMP", "test_USR", "testsize"] 
        }, 

        "to_server": { 
            "user": "test.local\\user", 
            "pass": "password", 
            "host": "ホスト名", 
            "to_path": "C:\\Users\\Use\\Desktop\\サーバーBディレクトリ" 
        } 

    } 
] 
PowerShellをリモートコンピューターで実行 - マイクロソフト系技術情報 Wiki
Linux からの WinRM アクセスを許可する
PowerShell リモート処理 - PowerShell
PowerShell でリモート コンピューターに対してコマンドを実行するには、さまざまな方法があります。
リモートトラブルシューティングについて - PowerShell
PowerShell でリモート操作のトラブルシューティングを行う方法について説明します。

コメント