SEブログ

【PowerShell】ファイルを比較する方法

こんにちは!SE ブログの相馬です。

 

 

 

今回は、PowerShell を使ってテキストファイルの中身を比較してみました。

 

 

普段は皆さんは作業される時にデータの比較などされているかと思います。実際に作業で使うデータに誤りがある事を避ける為ですが、WinMerge などのツールを使って手動でされていますよね。

 

 

実は、PowerShell ではファイルの比較をする事ができます。つまり、スクリプト内でファイルの比較に問題が無ければコマンドを実行したりする事ができるわけです。これは便利ですよね。

 

 

 

スポンサーリンク

検証内容

 

 

実際の利用場面を想定して Active Directory のグループを使って、以下の事を想定し検証してみました。

 

 

背景としては、定期的に AD のグループにユーザーを大量に追加します。元データは毎回今までの追加分も含めて全量送られてきます。差分の抽出をする事が面倒なので以下の 2 つの方法を考えてみました。

 

  1. AD のグループに格納されているメンバと元データを比較させて、差分だけ AD のグループに追加する。
  2. AD のグループに格納されているメンバを一旦全て削除し、元データにあるメンバを AD のグループに追加する。

 

 

 

スポンサーリンク

スクリプト

 

 

処理の大まかな流れとしては以下になります。

 

  1. AD のグループは AllUsers がある事を前提としています。
  2. AD のグループに読み込ませる為に、事前にテキストを準備してあります。→ AllUsers1.txt
  3. AD のグループに読み込ませたらテキストにエクスポートしています。→ AllUsers2.txt
  4. AD のグループに正しくメンバが追加されたか、テキストを比較します。

 

 

 

ステップ毎に処理の順序は以下になります。

 

  1. 事前に準備したテキストを変数に格納
  2. AD のグループから全てのメンバを削除
  3. 準備したテキストを AD のグループにインポート
  4. ADのグループからメンバをテキスト(AllUsers2.txt) にエクスポート
  5. 用意したテキストファイルを読み込んでヘッダにある User を削除
  6. 5. で読み込んだテキストファイルを保存
  7. テキストファイルを変数に格納
  8. Compare-Object でファイルを比較
  9. 比較結果、データが同じであれば返り値に OK を返し、そうでなければ NG を返す

 

 

ではスクリプトを書いてゆきます。

 

$AllUsers1 = "C:\Work\AllUsers1.txt"

Get-ADGroupMember "AllUsers" | `
ForEach-Object { `
    Remove-ADGroupMember "AllUsers" $_ -Confirm:$false
}

Import-CSV -Path $AllUsers1 | `
ForEach-Object { `
    Add-ADGroupMember -Identity "AllUsers" -Members $_.'User' -Confirm:$false `
}

$AllUsers2 = Get-ADGroupMember "AllUsers" | ForEach-Object {$_.SamAccountName}
$AllUsers2 = $AllUsers2 | out-file "C:\Work\AllUsers2.txt"
$AllUsers1 = "C:\Work\AllUsers1.txt"
$AllUsers1 = Get-Content $AllUsers1
$AllUsers1[1-1] = $null
$AllUsers1 | Out-File "C:\Work\AllUsers1.txt" -Encoding UTF8

$AllUsers1 = Get-Content "C:\Work\AllUsers1.txt"
$AllUsers2 = Get-Content "C:\Work\AllUsers2.txt"

$Compare = Compare-Object -ReferenceObject $AllUsers1 -DifferenceObject $AllUsers2

If ($Compare.SideIndicator -contains "<=") {
    Write-Host "NG"
        } Else {
    Write-Host "OK"
        }
}

 

 

 

差分のみ追加する場合は、以下のスクリプトでできました。

 

# ファイル作成
Write-Output "user " | Add-Content "C:\Work\AllUsers1.txt" -Encoding Default
Write-Output "---- " | Add-Content "C:\Work\AllUsers1.txt" -Encoding Default

# ADのグループからメンバをCSVにエクスポート
Get-ADGroupMember "AllUsers" | Select -ExpandProperty SamAccountName | Add-Content "C:\Work\AllUsers1.txt" -Encoding Default

# CSVからユーザを抽出してテキストに出力
$AllUsers2 = Import-Csv -Path "C:\Work\AllUsers2.csv"
$AllUsers2 = $AllUsers2 | Select-Object user | out-file "C:\Work\AllUsers3.txt"
$AllUsers2 = Select-String -Pattern "\S" -Path "C:\Work\AllUsers3.txt" | %{$_.line}
$AllUsers2 | out-file "C:\Work\AllUsers4.txt"

# 変数に格納
$AllUsers1 = Get-Content "C:\Work\AllUsers1.txt"
$AllUsers2 = Get-Content "C:\Work\AllUsers4.txt"

# 比較
$Compare = Compare-Object -ReferenceObject $AllUsers1 -DifferenceObject $AllUsers2
$Compare.Count

If ($Compare -eq $Null) {
    New-Item -Path "C:\Log\Result.log" -ItemType File
    $Result = "C:\Log\Result_NG.log"
    Write-Output "$(Get-Date): 差分がないので追加できません。" | Out-File -FilePath $Result -Append
    Exit
} Else {
    Write-Output user | Add-Content "C:\Work\AllUsers1_only.txt" -Encoding Default
    Write-Output user | Add-Content "C:\Work\AllUsers2_only.txt" -Encoding Default
    $AllUsers1 | where {$AllUsers2 -notcontains $_} | Add-Content -Path "C:\Work\AllUsers1_only.txt" -Encoding Default
    $AllUsers2 | where {$AllUsers1 -notcontains $_} | Add-Content -Path "C:\Work\AllUsers2_only.txt" -Encoding Default
}

# 追加
Import-CSV -Path "C:\Work\AllUsers2_only.txt" | `
ForEach-Object { `
    Add-ADGroupMember -Identity "AllUsers" -Members $_.'user' -Confirm:$false `
}

# 最終確認
Write-Output "user " | Add-Content "C:\Work\Result.txt" -Encoding Default
Write-Output "---- " | Add-Content "C:\Work\Result.txt" -Encoding Default
$Result = Get-ADGroupMember "AllUsers" | Select -ExpandProperty SamAccountName
$Result | Add-Content "C:\Work\Result.txt" -Encoding Default

$AllUsers1 = Get-Content "C:\Work\AllUsers4.txt"
$AllUsers2 = Get-Content "C:\Work\Result.txt"

$Compare = Compare-Object -ReferenceObject $AllUsers1 -DifferenceObject $AllUsers2

If ($Compare.SideIndicator -contains "<=") {
    New-Item -Path "C:\Log\Result_NG.log" -ItemType File
    $Result = "C:\Log\Result_NG.log"
    $AllUsers1 | where {$AllUsers2 -notcontains $_} | out-file "C:\Log\Result_AllUsers1.log"
    $AllUsers2 | where {$AllUsers1 -notcontains $_} | out-file "C:\Log\Result_AllUsers2.log"
    Exit
} Else {
    New-Item -Path "C:\Log\Result_OK.log" -ItemType File
    $Result = "C:\Log\Result_OK.log"
    Write-Output "$(Get-Date): 差分はありません。" | Out-File -FilePath $Result -Append
    Exit
}

 

 

 

まとめ

 

 

以上となります。いかがでしょうか。

 

 

送られてくる元のデータによって処理の内容が異なるかと思います。追加分のデータだけ送られてくるのであればこの方法は使えませんので、差分のみ追加するスクリプトを書くことになりますので環境によって書くスクリプトが異なるわけです。

 

 

この記事を書いているにあたりまだまだ PowerShell というか、処理の書き方についてもっと修行が必要だなぁと思いました。とはいえ良い経験になりました。

 

 

それでは最後までお読みいただきありがとうございました!