PowerShellプラクティス:Windowsバックアップバックアップストレージの監視

CPAP

この記事では、Powershellスクリプトを使用してWindowsバックアップによって作成されたバックアップファイルのストレージを監視し、バックアップの適時性と生成データのサイズを制御する実装について説明します。 また、Powershellプログラミングの便利なテクニックの例を紹介することも目的としています。

長い紹介


スケジュールに基づいて動作し、管理者に時々困難な農場の状況を通知するバックアップ管理システムがあると便利です。 良い、そして一見、あまり高価ではない:良い、この種の商用システムと無料システムの両方の選択は今やかなり広い。 ただし、稼働状態でのそのようなシステムの展開と保守の両方の面倒さのレベル、およびそのハードウェアコストは、ITシステム自体のある程度の合理的な最小の複雑さを意味し、そのデータがバックアップされることになっています。 たとえば、小規模オフィスのニーズに対応するBaculaの展開、約12台のWindowsワークステーションの数、たとえば2台または3台のサーバーがある場合、企業の最終製品のコンテキストでの非生産的な時間と材料リソースの支出であり、これの唯一のプラスの結果アクションは、システム管理者が得た実践的な体験です。 優れたレベルの機能と比較的高い自律性を提供する分散型バックアップシステムを検討すると、Veeam Endpoint Backupのような商用製品につながります。

残念ながら、このようなプログラムの無料版は、組み込みのWindowsバックアップより優れた利点を自慢できる場合、これらの利点はすべての人に関係するわけではなく、すべての場合に当てはまるわけではなく、常に明らかではありません。 そして、率直に言って、シャドウコピーメカニズムの「ネイティブ」サポートは大きなプラスです。 一言で言えば、すべての道がこのWindowsバックアップそのものにつながるという感覚が時々あります。 実際、バックアップシステムの選択と編成の問題は、特定のケースごとに純粋に個別のものであり、主観的な要因の背景に対して対処されています。 ただし、いずれにせよ、信頼性が高く安定したシステムを作成し、さらに保守が容易です。 しかし、自律的なバックアップエージェントは、組織の規模の一般的な監視機能を誇ることはできません。 これで、すぐに退屈しないように、この紹介を完了する時が来たと思います。

私たちの舞台裏は次のとおりです。Windows7およびWindows 10を実行しているコンピューターが多数あり、Windows Server 2008を実行しているサーバーもあります。データバックアップストレージとして使用するために購入したNASもあります。 タスクは、追加の予算なしで、複雑ではないがかなり信頼できる種類のバックアップを提供することです。 組織には常勤のシステム管理者がいないため、一部のユーザーの助けを借りてパートタイムの管理者がすべてのIT問題を解決するなど、簡単です。 Windowsバックアップのツールを使用することが決定されました。このツールは、各コンピューターのローカルスケジュールに従って、ネットワーク名「SA-NAS」のリモートマシン上の「netbackup」という名前の専用フォルダーにデータを保存します。 さらに、このソリューションは十分に安定しており、各コンピューターはバックアップに関するレポートをシステム管理者のメールに定期的に送信します(スクリプトによってシステムログから読み取られます)。 ただし、Windowsバックアップは対話型以外の方法でこの情報を共有する場所がないため、作成されたアーカイブのボリュームと「鮮度」を分析する問題は未解決のままです。 システム管理者は袖をまくり、別のスクリプトの作成を開始しました。このスクリプトでは、まずWindowsバックアップで作成されたバックアップコピーのデータ構造を整理する必要がありました。 だから...

Windowsバックアップを作成するものとその構成方法


この質問に答えるには、完全にオデッサスタイルで「具体的にどういう意味ですか?」という質問をする必要があります。Windowsバックアップでは、ご存じのとおり、コンピューターファイルシステムの選択した要素のバックアップコピーを作成できます。 ファイルアーカイブ(ファイルバックアップ)、および(b)ディスクボリュームのイメージ(イメージバックアップ)。 コントロールパネルの対応するアプレットを使用して構成するときに、特定のコンピューターのバックアップの種類を選択します。ご存じのように、特定のフォルダーとファイルのみをアーカイブする方法を指定し、選択したディスクボリュームのイメージを作成し、これら2つの方法を組み合わせます。 記事のトピックから離れて、この操作の説明に入るのは簡単なことではありません。詳細については、関連するドキュメントとインターネット検索エンジンに読者を送ってください。 Windows Backupのデータ構造に関する私自身の研究からのデータを引用します。ファッショナブルな「リエンジニアリング」という言葉は、タスクが比較的単純であるために控えめと呼ぶことができます。 また、ファイルシステムディレクトリのテキストの後半で「フォルダ」という用語を使用することにも注意してください。そのため、Windowsバックアップディレクトリファイルに関連してのみ使用される「ディレクトリ」という用語と混同しないようにします。

ターゲットメディア上の2つのバックアップモードのそれぞれでWindowsバックアップによって作成されたデータセットは、構造が異なります。

図1 最初の図は、ファイルモードでバックアップするときにターゲットネットワークフォルダー「netbackup」に作成されるファイルシステムフォルダー構造の典型的な例を示しています。 まず、サービスファイル「MediaID.bin」がルートフォルダーに表示されます。 明らかにわかるように、階層の最初のレベル(コンピューターレベル)では、コンピューターごとに個別のサブフォルダーが作成されます(「PC-001」、「PC-002」など)。 これらのフォルダーには、少なくとも2つのユーティリティファイル「MediaID.bin」「Desktop.ini」が含まれています。

各コンピューターの個々のフォルダーには、Windowsバックアップが機能するため、2番目の階層レベル(アーカイブレベル)のサブフォルダーが「 バックアップセット<日付> <時間>」タイプの名前で表示されます。各名前には1つのアーカイブが含まれます。それに基づいて、増分バックアップ。 また、各アーカイブレベルフォルダーには、 「Catalogs」という名前のサブフォルダーが含まれています。このフォルダーには、 「GlobalCatalog.wbcat」という名前のファイルが含まれています(このアーカイブのディレクトリが含まれています)。

このファイルは、データ構造とそのステータスの分析に非常に役立ちます。Catalogsフォルダーに存在することは、まず、このフォルダーとその近隣がアーカイブレベル(ボリュームレベル)内にあり、次に分析最終変更の時刻により、このアーカイブを更新した最後のバックアップ操作がいつ実行されたかを知ることができます。

最初の完全コピーと後続の増分コピーの両方が、 「Backup Files <date> <time>」という形式の名前のボリュームレベルの個別のサブフォルダーにあります。 アーカイブレベルと同様に、ボリュームレベルの各フォルダーにはサブフォルダー「Catalogs」が含まれますが、アーカイブレベルの名前とは異なり、特定のアーカイブボリュームのディレクトリを構成する拡張子「.wbcat」および「.wbverify」のファイルがかなり含まれます。 。 「カタログ」サブフォルダーに加えて、このレベルの各フォルダーには、特定のボリュームからのデータをまとめて含む任意の数のZIPアーカイブのみが含まれます。 すべてが非常にシンプルで、素晴らしいことですが、極端な場合、ZIPアーカイブを解凍するだけでデータを手動で抽出できます。

構成され実行されているWindowsバックアップは、パチンコからリリースされた石と同じように影響を受ける可能性があるため、増分ボリュームで現在のアーカイブの追加を停止し、新しいボリュームを初期化する決定は、このプログラムのコードの奥深くで行われ、他の人には知られないアーカイブレベルの新しいフォルダの形式。 この記事の著者は、プログラムによってそのような決定を下すためのアルゴリズムを見つけることができませんでしたが、論理的(そして経験の文脈で正当化された)は、増分ボリュームのチェーンを継続できる可能性と最後のバックアップ操作の成功との関係であるようです。 さらに、Windowsバックアップは新しいアーカイブを作成したため、その前身を完全に忘れ、システム管理者の完全な裁量にその運命を静かに委ねています。 もちろん、これは、管理者が古いアーカイブのフォルダーを何らかの方法で削除するまで、すぐに空きディスク容量に影響します。 おそらく、これにより同じファイルの複数のバックアップが保証されます(エクスプローラーのファイルプロパティウィンドウの[以前のバージョン]タブを参照)。 まあ、それは何ですか-Windowsバックアップ-これはそれです:事実上無料の製品から制限がないことを期待するのは難しいです。

ファイルタイプアーカイブのストレージ構造の問題に十分な明確性が導入されていると仮定して、ディスクボリュームのイメージに目を向けます。 この場合のディレクトリ構造(下図を参照)は、Windowsバックアップファイルアーカイブのディレクトリ構造と非常に似ていますが、大きな違いもあります。

画像
  1. フォルダー階層の最初のレベルは、ディスクモードでバックアップするときにターゲットフォルダー(「netbackup」)に作成される「WindowsImageBackup」フォルダーによって形成されます。 個々のコンピューターのサブフォルダーは、 「WindowsImageBackup」内に作成され、コンピューターのレベルを形成します。
  2. 各コンピューターのサブフォルダー内(アーカイブレベル)には、3つのフォルダーのみがあります。 それらの2 つには静的な名前があります: 「Catalogs」「SPPMetadataCache」 、および3番目のアーカイブフォルダーは、 「Backup <date> <time>」という形式の名前を持っています。

各コンピューターレベルのフォルダーには、上記の3つのサブフォルダーに加えて、拡張子のないMediaIdサービスファイルが常に含まれています。 一方、Catalogサブフォルダーには、常にGlobalCatalogBackupGlobalCatalogの 2つのファイルが含まれています。

このコンピューターがディスクボリュームイメージモードでバックアップされるたびに、アーカイブフォルダー(名前は「Backup <date> <time>」 )の名前が変更されます。 ボリュームの増分ではなく完全なアーカイブが実行されるたびに、これは論理的です。 しかし、このモードでは古いアーカイブがすぐに自動的に削除され、アーカイブファイルモードの古いアーカイブが同じ場所にあり続ける理由は謎のままです。 いずれにせよ、このフォルダーにはVHDファイル(仮想ディスクイメージ)のセットと補助XMLファイルのグループが含まれますが、その中で“ BackupSpecs.xml”を強調表示します。 どうやら、特定のアーカイブのパラメータを保存する役割を果たし、ディスクボリュームのイメージファイルを実際に作成した後に形成されるため、アーカイブ操作の完了時間を判断できます。

実際、Windowsバックアップのアーカイブストレージの構造に関する重要な情報と見なすことができるのはこれだけです。 Windowsは一部のフォルダーに形成する習慣があるというDesktop.iniファイルを見る意味がありません。これらは監視に関与していないためです。

私たちのアルゴリズム


自動的に受信したい情報を決定します。 次の一連の属性とします。


ファイルモードで作成されたWindowsバックアップアーカイブの場合、情報を収集するためのアルゴリズムは次のようになります。

  1. ターゲットフォルダーの最初のネストレベルのサブフォルダーを順番に検索し、個々のマシンのアーカイブのルートフォルダーのフラグである「MediaID.bin」ファイル(以下、簡潔にするためにKPAM)を含むサブフォルダーを特定します。
  2. 識別された各KPAMで、GlobalCatalog.wbcatファイルを含むCatalogsフォルダーのサブフォルダー内の存在を分析します。
  3. 前の手順で見つかったGlobalCatalog.wbcatファイルの中から最新のものを選択し、その親フォルダーを含むフォルダーを最新のファイルモードアーカイブ(以下、CAAと呼びます)のリポジトリーとして受け入れます。 このファイルの最後の変更の時間を、このアーカイブの最後のボリュームの形成が完了した時間とみなします。
  4. CAAフォルダーのサブフォルダー内のZIPファイルのサイズを要約し、この値をCAAのサイズとして使用します。
  5. 蓄積された情報のユーザービューを作成して返します。名前(パス)、サイズ、およびCPAMリストから各マシンのCAAを作成した時間です。

ディスクボリュームモードのアーカイブの場合、データ収集アルゴリズムは次のようになります。

  1. ターゲットフォルダーのネストの最初のレベルのサブフォルダーを順次検索し、 「MediaID」ファイルを含むサブフォルダーを特定します。これは実際には個々のマシンのアーカイブのルートフォルダーのフラグです(以下、簡潔にするためにKPAM)。
  2. 各CPAMでは、 「BackupSpecs.xml」という名前のサブフォルダー内のファイルの存在を分析します。 念のため、1つではなく複数のアーカイブフォルダーが存在する可能性から進めます。
  3. 前の手順で見つかったBackupSpecs.xmlファイルの中から最新のものを選択し、それを含むフォルダーをディスクボリュームモードの最新のアーカイブ(以降-CAA)のリポジトリとして受け入れます。 このファイルの最後の変更の時間を、このアーカイブの形成の完了時間とみなします。
  4. CAAフォルダーのサブフォルダーにあるVHDファイルのサイズを要約し、この値をCAAのサイズとして使用します。
  5. 蓄積された情報のユーザービューを作成して返します。名前(パス)、サイズ、およびCPAMリストから各マシンのCAAを作成した時間です。

これまでのところ、すべては実装を含めて十分にシンプルに思えます。 そしてPowershellスクリプトの形式で、始めましょう。

Powershellスクリプト


このセクションでは、スクリプトの重要な要素を検討します。実装の詳細が省略されているため、 添付のソースコードを参照することを提案します。 次のコード例のユーザーインターフェースのテキスト要素はロシア語ですが、英語でスクリプトに実装されています-英語環境で使用するために単純に設計されており、言語基準に従ってコードのバージョンをコーディングしたくありませんが、実装は多言語対応ですこのような単純な製品の場合、インターフェースは不合理に複雑です。

ファイルモードのアーカイブ処理


まず、KPAMのリストを取得します。

function Get-MachineListFB ($WinBackupRoot) { $MachineRoots = @{} Get-ChildItem -Path $WinBackupRoot -Recurse -Depth 1 -File -Filter "MediaID.bin" | Where-Object {$_.Directory.FullName -ne $WinBackupRoot} | foreach { $MachineRoots[$_.Directory.Name]=$_.Directory.FullName } return $MachineRoots } 

Get-MachineListFB関数は1つのパラメーターを取ります。Windowsバックアップアーカイブストレージのルートフォルダーのフルネームであり、 ご覧のとおり 、コードに複雑なものはありません。 Get-ChildItemコマンドレットは、指定されたフォルダーに関して同じネストレベル内にあるファイル記述子オブジェクト「MediaID.bin」のリストを生成します。 このリストはWhere-Objectコマンドレットにパイプされ、サブフォルダー内の指定されたフォルダーのルートの外側にあるファイルのみを次のステージにスキップします(思い出すように、Windowsバックアップアーカイブストレージのルートフォルダーには「MediaID.bin」というファイルも含まれています" )。 次に、返されたオブジェクトには、見つかったファイルを含むフォルダーの名前と完全パスが入力されます。

Get-ChildItemコマンドレットを使用して、指定された基準に従ってファイルとフォルダーを選択することについて、発言したいと思います。 ご覧のとおり、コマンドレットの名前の基準は「-Filter」パラメーターの形式で表されます。 同時に、 Get-ChildItemには、同じ機能を実行できる別のパラメーター"-Include"もあります。 違いは何ですか?選択基準を説明する方法を選択する方法は? "-Filter"パラメーターを使用する場合、 Powershellは特定のデータセット(この場合はディスクファイルシステム)へのアクセスを提供する適切なプロバイダーメカニズムを使用して選択を実行します。 または、Powershellには独自の組み込み選択メカニズムがあり、 「-Include」パラメーターによって有効になります。 ユーザーにとっての違いは、次のとおりです。

  1. パフォーマンス:プロバイダーメカニズムを使用した選択は、PS独自の機能よりも速くなる可能性があります(この場合は確かです)。
  2. 機能: 「-Include」パラメーターと「-Recurse」パラメーターを一緒に使用すると、階層の深さの制限は「-Depth」パラメーターと連動しません(少なくとも-ディスクファイルシステムに適用されるPowershellバージョン5では、これは実験的に確立されました)。

次に、CAA検出機能を実装します。

 function Get-LastFileBackupSet ($MachineRoot) { $objLB = $null try { $LastWbcat = Get-ChildItem -Path $MachineRoot -Recurse -Depth 2 ` -File -Filter "GlobalCatalog.wbcat" | Where-Object {$_.Directory.Name -eq "Catalogs"} | Sort-Object LastWriteTime | Select-Object -Last 1 LastWriteTime, Directory, ` @{Name="Machine";Expression={$_.Directory.Parent.Parent.Name.ToUpper()}}, ` @{Name="Path";Expression={$_.Directory.Parent.FullName}}, ` @{Name="Name";Expression={$_.Directory.Parent.Name}} $ZIPFiles = ( Get-ChildItem $LastWbcat.Directory.Parent.FullName -Recurse -Depth 2 ` -File -Filter "*.zip" | Select-Object Length | Measure-Object -Property Length -Sum ) } finally { if (($ZIPFiles) -and ($LastWbcat)) { $objLB = @{ Machine = $LastWbcat.Machine Path = $LastWbcat.Path Name = $LastWbcat.Name Updated = $LastWbcat.LastWriteTime Size = $ZIPFiles.Sum } } } return $objLB } 

Powershellの新規ユーザーに説明しましょう。PSスクリプト言語の次の行で式を継続するための標準文字は、いくつかの行の末尾にある単一のバックティックです。 ここでは、記事内のコードサンプルの読みやすさを改善するためにのみ使用されます。

関数のロジックを明確にしましょう。 彼女の呼び出しパラメーターは、前のものと同様に、1つだけです:単一のマシンのファイルモードアーカイブのルートフォルダーのフルネーム( 事前にGet-MachineListFB関数を使用して、アーカイブが見つかったすべてのマシンのこれらのパスを決定します)。 Get-ChildItem呼び出しは、指定されたフォルダーのサブフォルダーにある「GlobalCatalog.wbcat」という名前の見つかったファイルの説明を含むオブジェクトのリストを返します。 このリストはWhere-Objectコマンドレットの処理に渡され、見つかったファイルの中から、親フォルダーの名前が指定されたファイル( "Catalogs" )と一致するファイルのみを選択します。 パイプラインの次のステップは、最後のファイル変更のタイムスタンプの昇順でリストの残りを並べ替えるSort-Objectコマンドレットです。Select-Objectコマンドレットは、順序付けられたリストの最後の要素を選択し、マシンリソースを節約するために返されたオブジェクトの属性セットをLastWriteTimeおよびDirectory絞り込みます。

副詞の「単純な」終了を伴うのはそれだけです。その後、 Select-Objectコマンドレットは、返された各オブジェクトに追加のユーザー属性を追加します(PSではそのようなことをその場で行うことができます)。 その結果、戻り値はソース要素の2つの「ビルトイン」 Directory プロパティLastWriteTimeプロパティで構成された属性と、動的に計算されたユーザー定義プロパティMachinePathNameを定義したオブジェクト(ハッシュテーブル形式)です。 この種類のユーザー属性を定義するための形式は次のとおりです。

 @{Name = "<_>"; Expression = {$_.<>}} 

プロパティの値を計算する式は、処理中のデータに直接関連しない任意のもの(例: Get-Date )、またはこの関数のコードで行われているように、 $ _ iterator要素のプロパティとメソッドを含めることができます。 関数コードの例からわかるように、この種の構造はSelect-Objectコマンドレットによって返されるパラメーターのリストに単純にリストされています。

計算の結果を複合オブジェクトの形式で返すことは、同じソースデータセットのさまざまなパラメーターに対して個別の計算を行う必要がないため便利です。 特に、調べたばかりの関数は、CAAフォルダーの名前だけでなく、そのフルパス、その中のアーカイブの最終更新のタイムスタンプ、およびそのサイズも示します。

さらに関数テキストに沿って、GlobalCatalog.wbcatファイルの親フォルダーを含むフォルダーの1レベル上のフォルダーのすべてのサブフォルダーで「ZIP」拡張子を持つファイルを選択することにより、このアーカイブを構成するZIPファイルの合計サイズを計算します。このアーカイブのフォルダ内)。 Get-ChildItem呼び出しは、 Select-Objectコマンドレットに渡されるファイルのリストを返します。Select-Objectコマンドレットは、データからLengthプロパティのみを抽出し(ファイルシステムオブジェクトのサイズシノニムです)、結果の選択結果をMeasure-Objectコマンドレットに渡して、サイズを集計します。

条件の構築($ZIPFiles) -and ($LastWbcat)は、エラー状態の基本的な検出を目的として、変数$ ZIPFilesおよび$ LastWbcatの存在を確認するのに役立ちます。 これは標準的なPowershellのトリックです:これらの変数を事前に初期化していないため、テスト時に初期化されていない変数のいずれかが許容値を持たない場合、テストは論理的な意味で論理的な結果を返します。 つまり If Not IsNull() … Visual Basicのコンストラクトのようなもの。

さらに-おそらく明らかなように-オブジェクトのフィールド(「ハッシュテーブル」など)への計算値の割り当て$ objLBが実行され、関数によって返されます。

特定のマシンのCAAパラメータを決定すると、実際に計算アルゴリズムが完了します。これは、目的のCAAについてすべてがわかっており、この「すべて」がGet-LastFileBackupSet関数によって返されるオブジェクトのフィールドに書き込まれるためです:


受け取った情報の表示を実装することは残っています。 システム管理者は消費者であるため、視覚的スタイルの改良は行わず、出力データの2つの表現、プレーンテキストと表形式のHTMLを作成します。 各形式について、2つの関数を作成します。1つ目は個々のコンピューターのデータ行を生成し、2つ目はそのような行から見出しを持つテーブルを収集します。 実際、スクリプトコードでは逆順で実行されます。Powershellエグゼクティブサブシステムはインタープリターであるため、スクリプトコード内の関数宣言は呼び出しの前に行う必要があり、PSは関数プロトタイプの予備宣言のメカニズムをサポートしていません。

 function Get-LastFileBackupSetSummaryTXTRow ($MachineRoot) { $ret = "" $Now = Get-Date $LastBT = Get-LastFileBackupSet ($MachineRoot) if ($LastBT) { $ret = ": " + $LastBT.Machine + "; : " + $LastBT.Name + ` "; : " + ($Now - $LastBT.Updated).Days + "  . (" + ` $LastBT.Updated + "); : " + ('{0:0} {1}' -f ($LastBT.Size/1024/1024), "") } else{ $ret = "  " } return $ret } function Get-LastFileBackupDatesTXT ($WinBackupRoot) { $table="  :`r`n" $MachineRoots = Get-MachineListFB ($WinBackupRoot) foreach ($machine in $MachineRoots.Keys) { $line = Get-LastFileBackupSetSummaryTXTRow($MachineRoots[$machine]) $table+= -join($line, "`r`n") } return $table } 

Get-LastFileBackupDatesTXTコレクター関数は完全に簡単です。ヘッダーを持つテーブルを含む段階でテキスト文字列を作成するだけです。 テーブル行はGet-LastFileBackupSetSummaryTXTRow関数によって生成され、その「接着」は文字列連結演算子「-join」によって実行されます。 文献では、それは異なって呼ばれています:どこで-オペレータによって、そしてどこで-メソッドによって、そしていくつかの書き方があります。 ここでは、区切り文字なしでデフォルトで連結が行われる「関数のような」表記法を使用します。 2番目のオペランドは、行末のEsc文字とキャリッジリターン( "r"および"n" )で構成される文字列定数です。 Windowsテキストファイルの標準的な行の折り返し。

Get-LastFileBackupSetSummaryTXTRow関数は、CPAMへのパスを取得し、対応するマシンのCAAを決定します。 この値は複合であるため、そこから個々のデータ要素を抽出し、それらにテキストラベルを付けて、読み取り可能な文字列を収集します。 ここでPowershellは、操作対象の値のオブジェクトの性質の喜びを使用することができます:オブジェクトタイプ「日付/時刻」の2つの値の差もオブジェクトであり、日数での値は追加の関数を使用せずに単純な減算演算子によって計算されます 結果を取得する測定単位を明確にするだけで済みます。これは、結果のオブジェクトのDaysプロパティを示すことで実現されます。これは、関心のある日だからです。

アーカイブサイズの値をメガバイト単位で表現するために、次の構成が使用されました。

 ('{0:0} {1}' -f ($LastBT.Size/1024/1024), "") 

これはフォーマット演算子であり、多くのプログラミング言語のフォーマット機能に類似しています。 外部ブラケット(読みやすくするためにここに残されています)の中には、フォーマットの文字列、演算子自体( "-f" )、および置換値のリストが順番に配置されています。 書式の行には、2つの書式指定子が含まれています(各指定子は中かっこで囲まれています)。 書式指定子の間にスペースがあるため、値間の結果の行に存在します。 それぞれ演算子の後に、2つの値が続きます。サイズをメガバイト単位で計算する式と、測定単位の文字列です。 出力では、「123 MB」という形式の文字列値を取得します。 Powershellは、指定された数値形式で、指定された形式に一致する型に数値をキャストします。

CAA値が空の場合、 LastFileBackupSetSummaryTXTRowはエラー状況を示す文字列を返します。

情報のハイパーテキスト表現は、単純なHTMLタグが生成された行に挿入されるという点でのみ、本質的に異なり、同様の方法で形成されます。 問題のアルゴリズムに関して根本的に新しいものは何もないため、ここではこのコードを提供しません。記事に添付されているスクリプトのソースコードを調べることで、このコードに慣れることができます。 HTMLコードのフォーマットには、管理者の注意を引くために、1日以上前にCAAで色分けされた文字列が含まれていることに注意してください。

ディスクボリュームイメージモードアーカイブの処理


このモードのアーカイブの詳細を考慮して、前のケースと同様にCPAMのリストを取得します。

 function Get-MachineListIB ($WinBackupRoot) { $MachineRoots = @{} $ImageBackupRoot = $WinBackupRoot+"\WindowsImageBackup" Get-ChildItem -Path $ImageBackupRoot -Recurse -Depth 1 -File -Filter "MediaID" | foreach { $MachineRoots[$_.Directory.Name]=$_.Directory.FullName } return $MachineRoots } 

つまり サブフォルダーを検索して、リポジトリのルートフォルダーにある「WindowsImageBackup」という名前のサブフォルダーを同じレベルの深さまで調べます。 KPAMを意味する「MediaID」という名前の信号ファイルを探しています。

ファイルモードアーカイブの場合と同様に、 Get-LastImageBackupSet関数を記述し、テキストおよびハイパーテキスト形式で結果のユーザー定義表現を生成するために、 Get-LastImageBackupSetSummaryTXTRowGet-LastImageBackupSetSummaryHTMLRowGet-LastImageTackTackDateを使用してCAAを定義します。 ファイルモードアーカイブの場合の考慮事項と同様に、ハイパーテキスト表現を生成する関数のペアはここには示されていません(添付のソースコードを参照)。

 function Get-LastImageBackupSet ($MachineRoot) { $objLB = $null try { $LastBSXML = Get-ChildItem -Path $MachineRoot -Recurse -Depth 1 ` -File -Filter "BackupSpecs.xml" | Sort-Object LastWriteTime | Select-Object -Last 1 LastWriteTime, Directory, ` @{Name="Machine";Expression={$_.Directory.Parent.Name.ToUpper()}}, ` @{Name="Path";Expression={$_.Directory.FullName}}, ` @{Name="Name";Expression={$_.Directory.Name}} $VHDFiles = ( Get-ChildItem $LastBSXML.Directory.FullName -File -Filter "*.vhd" | Select-Object Length | Measure-Object -property length -sum -ErrorAction SilentlyContinue) } finally { if (($VHDFiles) -and ($LastBSXML)) { $objLB = @{ Machine = $LastBSXML.Machine Path = $LastBSXML.Path Name = $LastBSXML.Name Updated = $LastBSXML.LastWriteTime Size = $VHDFiles.Sum } } } return $objLB } function Get-LastImageBackupSetSummaryTXTRow ($MachineRoot) { $ret = "" $Now = Get-Date $LastBT = Get-LastImageBackupSet ($MachineRoot) if ($LastBT) { $ret = ": " + $LastBT.Machine + "; : " + ` $LastBT.Name + "; : " + ($Now - $LastBT.Updated).Days + ` "  . (" + $LastBT.Updated + "); : " + ` ('{0:0} {1}' -f ($LastBT.Size/1024/1024), "") } else{ $ret = "  ." } return $ret } function Get-LastImageBackupDatesTXT ($WinBackupRoot) { $table="  :`r`n" $MachineRoots = Get-MachineListIB ($WinBackupRoot) foreach ($machine in $MachineRoots.Keys) { $line = Get-LastImageBackupSetSummaryTXTRow($MachineRoots[$machine]) $table+= -join($machine, " => ", $line, "`r`n") } return $table } 

これにより、ストレージ分析コードの分析が完了し、レポート全体のアセンブリと出力を担当するスクリプトの一般的な部分に進みます。

アセンブリおよびレポート出力


スクリプトは、既に同意したとおり、プレーンテキスト形式とHTML形式のレポートを生成できる必要があるという事実から進めます。 さらに、レポートを次の2つの方法で出力できるようにするタスクを設定します。(a)標準出力デバイスへのテストストリームの形式、および(b)指定されたアドレスへの電子メール送信。 同時に、スクリプトは次のコマンドラインパラメーターを受け入れる必要があります。


最初に、コマンドラインパラメーターの説明を含むスクリプトヘッダーを作成します。 CMD.EXEスクリプトの初期形式で実装されたそれらを操作するメカニズムは、Windows Script Hostスクリプトで大幅に改善されましたが、それでも非常に不便であり、入力されたパラメーターのシステムを整理して分析するために多くの追加手順が必要であったことに言及する価値があります。 ただし、Powershellでは、根本的な変換を経て、宣言に基づいてPS組み込みツールを使用してパラメーター処理を実装できるParamブロックという本格的な便利なツールになりました。 私たち自身の目的にそれを適用します:

 Param( [Parameter(Mandatory)][string] $Root, [switch] $txt=$false, [switch] $mail=$false, [string] $SmtpSrv, [int] $Port=25, [string] $To, [string] $Fm, [string] $Pwd, [string] $Sub ) 

上記のスニペットからわかるように、aceコマンドラインパラメーターは1つのParamブロックで記述されています。 彼の括弧内に、彼の属性のコンマ区切りリストがリストされています-データ型と必須のすべてのパラメーター。 一般に、個々のパラメーターを記述する最も単純なオプションは、文字「$」で始まる単純な識別子で構成されます。 パラメーターを宣言するための次の最も難しいオプションは、データ型を改良することです。これは、パラメーターIDの左側にある角括弧内のデータ型の名前として記述されます。 デフォルト値を設定することもできます。デフォルト値では、右側の識別子に割り当て演算子と値を追加するだけで十分です。 デフォルト値を明示的に指定しないと、パラメーターは指定されたタイプの空の値に初期化されます。

スイッチパラメーターのタイプ(つまり、「スイッチ」)は次のように機能します。スクリプトがコマンドラインで簡単に言及してこのパラメーターを受け取った場合、真の値が割り当てられます。 コマンドラインにない場合は、偽の値が割り当てられます。

追加のパラメーター属性(必須など)を指定する必要がある場合は、左側に角かっこでブロックをもう1つ追加する必要があります。このブロックは、 Parameterキーワードで始まり、その後に属性のリストと、場合によっては括弧で囲まれた値が続きます。 特に、個々のパラメーターのバインディングは、 必須論理タイプの属性によって定義されます。 PS 3.0以降、属性値に明示的にTrueを指定することはオプションです。省略した場合、 Trueを意味します

たとえば、この例では、 Rootパラメーターは必須であり、タイプstringを持ち、デフォルト値はありません。 このパラメーターの指定された必須性は、それなしでスクリプトが実行される場合、Powershellインタープリターがコンソールにその値を入力するように促し、指定された値なしでスクリプトコードを実行できないようにするという事実につながります。 必須として宣言されていない明示的に指定されたパラメーターがないことは、スクリプト実行の開始に対する障害ではありません。

Powershellスクリプト言語でのParamブロックの使用は、コマンドラインパラメーターのみに限定されず、関数パラメーターに関しても使用できることを言わなければなりません。 おそらく、逆のステートメントであっても、より真実になるでしょう。関数パラメーターだけでなく、スクリプトコマンドラインパラメーターにも適用できます。スクリプトの本体は、プログラムコードの階層の最上位レベルの関数に類似しています(たとえば、Cのmain()関数として)。これにより、次のようにGet-LastImageBackupDatesTXT関数オーバーライドできます

 function Get-LastImageBackupDatesTXT { Param( [Parameter(Mandatory)][string] $WinBackupRoot ) $table="  :`r`n" $MachineRoots = Get-MachineListIB ($WinBackupRoot) foreach ($machine in $MachineRoots.Keys) { $line = Get-LastImageBackupSetSummaryTXTRow($MachineRoots[$machine]) $table+= -join($machine, " => ", $line, "`r`n") } return $table } 

必須パラメーターなしで関数を呼び出す場合、入力のプロンプトも画面に表示されますが、この場合の有用性は議論の余地があります。ただし、デフォルト値を設定し、パラメータをタイプ化する機能は、場合によっては間違いなく便利です。

この余談を完了するには、スクリプトパラメーターとPowershell関数を定義する形式に関して、スクリプトパラメーターの説明が自己文書化システムの一部であることに注意する必要があります。これらは、スクリプトコメントベースのヘルプテキストの「.PARAMETER」セクションで作成者が指定した情報と自動的に結合され、コマンド「Get-Help <スクリプト名>」で生成されたスクリプトのヘルプの一部として表示されます。

レポートの全文のアセンブリコードに移りましょう。上記で定式化された問題の最終的な声明に基づいて、スクリプト本文から直接呼び出される3つの関数があることは明らかです:レポートのテキストバージョンの組み立て、レポートのハイパーテキストバージョンの組み立て、および電子メールによるレポートテキストの送信:

 function Get-LastWinBackupDatesHTML ($WinBackupRoot) { $Now = Get-Date $table='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'+"`n" $table+='<html xmlns="http://www.w3.org/1999/xhtml"><head><title>   "'+ `$WinBackupRoot+'"</title></head><body>'+"`n" $table+='<h3>   "'+$WinBackupRoot+'"'+"</h3>`n" $table+='<h3>  : '+$Now+"</h3>`n" $table+= Get-LastFileBackupDatesHTML ($WinBackupRoot) $table+= Get-LastImageBackupDatesHTML ($WinBackupRoot) $table+= "</body>`n</html>" return $table } function Get-LastWinBackupDatesTXT ($WinBackupRoot) { $Now = Get-Date $table='   "'+$WinBackupRoot+'"'+"`r`n" $table+='  : '+$Now+"`r`n`r`n" $table+= Get-LastFileBackupDatesTXT ($WinBackupRoot) $table+= "`r`n" $table+= Get-LastImageBackupDatesTXT ($WinBackupRoot) return $table } function Send-Email-Report ($SendInfo, $TXTonly=$false){ $Credential = New-Object -TypeName "System.Management.Automation.PSCredential" ` -ArgumentList $SendInfo.Username, $SendInfo.SecurePassword if ($TXTonly) { Send-MailMessage -To $SendInfo.To -From $SendInfo.From ` -Subject $SendInfo.Subject -Body $SendInfo.MsgBody ` -SmtpServer $SendInfo.SmtpServer -Credential $Credential ` -Port $SendInfo.SmtpPort -Encoding UTF8 } else { Send-MailMessage -To $SendInfo.To -From $SendInfo.From ` -Subject $SendInfo.Subject -BodyAsHtml $SendInfo.MsgBody ` -SmtpServer $SendInfo.SmtpServer -Credential $Credential ` -Port $SendInfo.SmtpPort } } 

別に、Powershellに関係なく、プレーンテキストの行とHTMLのLFのみを分離するためにCR / LFを使用した理由を説明します。これは、MS OutlookでHTMLメッセージが正常に表示されるようにするために行われます。さて、通常のブラウザでレポートを見ると、違いはありません。

最終レイアウトの両方の機能は非常にシンプルであり、静的に定義されたテキストフラグメントで動作し、呼び出されたルーチンから受信したテキストブロックと組み合わされて、全体的なレポートを形成します。

機能送信-メール-報告書は、「ラッパー」コマンドレットで送信-はMailMessageスクリプトがこのコマンドレットのパラメーターの「座標系」で動作するパラメーターシステムを表示します。「System.Management.Automation.PSCredential」という名前の.NETクラスのインスタンスを使用して、ユーザーIDとパスワードをSend-MailMessageコマンドレットに渡す必要があることに注意してください。後者はこれらのパラメーターの通常の文字列値を受け入れないためです。使用されるクラスは、安全な(システムの観点から)コンテナー($ Credential変数)これらの値を保存します。これらの値は、従来のログイン/パスワードのペアの代わりにコマンドレットに渡されます。前述のように、厳密に言えば、オープンフォームでパスワードをスクリプトに送信することは、特別なGet-Credentialコマンドレット使用してスクリプト実行中にパスワードの直接ユーザー入力を使用して、そのようなデータを入力するためのシステムグラフィカルダイアログを表示することを提供するための安全で安全なオプションではありません。しかし、インタラクティブな起動ではなくバッチ用のスクリプトを作成しているため、ドグマからこのような逸脱を行う必要があります...

メッセージを送信する機能で終了します。メッセージに直接関与するパラメーターは$ SendInfoパラメーターにカプセル化されているため、パラメーターは2つしかありません。ハッシュテーブルであること。それとは別に、オプションの$ TXTonlyフラグパラメーターのみが渡され、プレーンテキスト形式でメッセージを送信する必要があることを示します。呼び出し中に省略されたり、偽の値を持つ場合、メッセージはハイパーテキスト形式で送信されます。

上記のすべての機能を使用するスクリプト本体コードのみを作成することは残ります。そのサイズと複雑さがこれらの関数の数に反比例するという仮定は完全に公平です-アルゴリズムの開発とそれに対応する関数の分解にそれほど多くの努力を費やしたのは無駄ではありません。

 if ($txt) { $Ret = Get-LastWinBackupDatesTXT ($Root) } else { $Ret = Get-LastWinBackupDatesHTML ($Root) } if ($mail) { if (($SmtpSrv) -and ($Port) -and ($To) -and ($Fm) -and ($Pwd) -and ($Sub) -and ($Ret)) { $objArgs = @{ SmtpServer = $SmtpSrv SmtpPort = $Port To = $To.Split(',') From = $Fm Username = $Fm SecurePassword = ConvertTo-SecureString -String $Pwd -AsPlainText -Force Subject = $Sub MsgBody = $Ret } Send-Email-Report ($objArgs, $txt) } else { Write-Host $Ret } } else { Write-Host $Ret } 

すべてが実際に非常に簡単になり、概略的に言うと、コマンドラインパラメーター$ txtがスクリプトに渡されたかどうかに応じて、2つの既存のGet-LastWinBackupDatesXXX関数の1つが呼び出されます。実行結果(実際には、生成されたレポートのテキスト)は$ Ret変数に保存されます。スクリプトのコマンドラインパラメーターで電子メールでの送信が必要な場合、Send-Email-Report関数を呼び出して、メッセージとその送信方法を完全に説明するハッシュテーブルを作成し、提供します。電子メールに関する話がなかった場合、および送信パラメーターの説明に明らかな欠陥がある場合、レポートのテキストを標準出力デバイス(コンソール)に表示するだけです。

生成されたレポートの例を提供します。

ハイパーテキスト形式:



「\\ sa-nas \ netbackup」のバックアップ


レポート生成日:01/10/2017 09:00:01


ファイルモードアーカイブ:



最新のアーカイブ


年齢


更新されました


大きさ


サチェン
バックアップセット2017-01-10 040000
0日
10/01/2017 04:16:23
6446 MB
SA-DOCTOR
バックアップセット2017-01-10 080002
0日
10/01/2017 08:10:09
2431 MB
SA-BAR
バックアップセット2016-12-28 033001
0日
10/01/2017 02:36:35
248028 MB
SA-RECEPTION
バックアップセット2017-01-10 060737
0日
10/01/2017 06:16:29
1264 MB
SA-ECR
バックアップセット2017-01-08 220005
0日
09/01/2017 22:03:22
2863 MB
SA-HOTELMGR
バックアップセット2017-01-08 020003
0日
09/01/2017 22:11:02
26788 MB
SA-ITO
バックアップセット2017-01-06 230005
0日
09/01/2017 23:08:48
17486 MB
SA-CHEF
バックアップセット2017-01-05 230002
0日
09/01/2017 23:02:11
3791 MB
SAマスター
バックアップセット2017-01-09 102958
0日
01/09/2017 23:12:51
8441
SA-CONTROLLER
Backup Set 2017-01-09 000007
0
01/10/2017 00:17:04
9788

:




年齢



大きさ


SA-ITO
Backup 2017-01-10 020013
0
01/09/2017 23:12:44
47534
POSSERVER
Backup 2017-01-10 020006
0
01/09/2017 23:07:36
23138



:




「\\ sa-nas \ netbackup」内のバックアップ
レポート生成日:2017年1月10日09:00:01

ファイルモードアーカイブ:
マシン:SA-CHENG;アーカイブ名:バックアップセット2017-01-10 040000;更新:0日前。 (2017年1月10日04:16:23);サイズ:6446 MB
マシン:SA-DOCTOR;アーカイブ名:バックアップセット2017-01-10 080002;更新:0日前。 (2017年1月10日08:10:09);サイズ:2431 MB
マシン:SA-BAR;アーカイブ名:バックアップセット2016-12-28 033001;更新:0日前。 (2017年1月10日02:36:35);サイズ:248028 MB
マシン:SA-RECEPTION;アーカイブ名:バックアップセット2017-01-10 060737;更新:0日前。 (2017年1月10日06:16:29);サイズ:1264 MB
マシン:SA-ECR;アーカイブ名:バックアップセット2017-01-08 220005;更新:0日前。 (2017/09/09 22:03:22);サイズ:2863 MB
マシン:SA-HOTELMGR;アーカイブ名:バックアップセット2017-01-08 020003;更新:0日前。 (2017/09/09 22:11:02);サイズ:26788 MB
マシン:SA-ITO;アーカイブ名:バックアップセット2017-01-06 230005;更新:0日前。 (2017/09/09 23:08:48);サイズ:17486 MB
マシン:SA-CHEF;アーカイブ名:バックアップセット2017-01-05 230002;更新:0日前。 (2017/09/09 23:02:11);サイズ:3791 MB
マシン:SA-MASTER;アーカイブ名:バックアップセット2017-01-09 102958;更新:0日前。 (09/09/2017 23:12:51);サイズ:8441 MB
マシン:SA-CONTROLLER;アーカイブ名:バックアップセット2017-01-09 000007;更新:0日前。 (2017年1月10日00:17:04);サイズ:9788 MB

ディスクボリュームイメージ:
マシン:SA-ITO;アーカイブ名:バックアップ2017-01-10 020013;更新:0日前。 (09/09/2017 23:12:44);サイズ:47534 MB
マシン:POSSERVER;アーカイブ名:バックアップ2017-01-10 020006;更新:0日前。 (2017/09/09 23:07:36);サイズ:23138 MB



おわりに


ここで説明するスクリプトは実際に使用され、システムタスクスケジューラを使用して起動されるバックアップストレージの状況を定期的に報告します。もちろん、それは不完全であり、さまざまな改善を簡単に提案することができます-たとえば、残りのディスク容量や古いアーカイブが占めるボリュームの制御などです。また、スクリプトで見落とされがちなエラー状況の処理の問題によって、創造性の広い範囲が提供されます。しかし、なんらかの方法で、このオプションは完全に機能し、開発にあまり時間を必要としませんでした。実際、私には思えますが、これはシステム管理者のレベルで開発されたスクリプトの意味です。商用製品のレベルではなくても、最小限のリソースで問題を効果的に解決します。

ここからスクリプトのソースコードを含むアーカイブをダウンロードします

この記事の続きである次の記事では、他の任意のバックアップシステム、特にNTバックアップとghettoVCB(VMware ESXiの場合)によって作成されたデータセットをサポートするフィルターアドオンテクノロジーを使用したこのスクリプトの機能の拡張について説明します。

Source: https://habr.com/ru/post/J319378/


All Articles