IT管理のマメ知識

ITについて個人の感想をアウトプットしているブログ

(powershell)xcopyコマンドでバックアップ世代管理

[powershell] xcopyコマンドでバックアップ

スクリプトの目的

  • このスクリプトは、Windows環境でバックアップ世代管理を行うことができるPowershellスクリプトです。
  • 重要なデータが含まれるフォルダを、ネットワーク接続された別コンピューターやNas等のデバイスにバックアップする際に使用することができます。もちろん、同じPCにUSB接続されたポータブルハードディスクでも構いません。

バックアップ対象のデータサイズが大きい場合の注意点

  • バックアップ方法は、対象フォルダ全体のレプリケーションですが、世代管理によりフォルダ分けされます。
  • そのためバックアップ世代数分のデータ容量が必要となります。バックアップ対象のデータ量が多く、また保持しておくたいバックアップ世代数が多いほど、多くのディスク容量を消費することになることに注意が必要です。
  • さらに、バックアップ対象のデータ量が多くなるにつれて、xcopyコマンド実行にかかる時間と、古くなったバックアップ世代のデータを削除するためにかかる時間が長くなりますので、所要時間についても考慮が必要となります。

概要

  • バックアップ処理は、xcopyコマンドを呼び出して実行しています。xcopyコマンドは、コピー手段としては信頼性が高いとされています。
  • バックアップ世代管理は、powershellが備えるコマンドにより実行しています。

  • どのようにバックアップが行われるか、下記の"サンプルコードの環境例", "実行ログのサンプル"を参照してください。

  • 実行環境に合わせたパラメータ設定方法を行ってください。
  • スクリプトVisual Studio Code上で作成しました。実行環境に合わせたパラメータ設定を行うために、ps1ファイルを編集して保存する場合は、文字エンコーディングを「utf8 With BOM」としてください。エンコードが異なると、パス名に含まれる日本語が文字化けしたり、うまく動作しなかったりするようです。

スクリプトに関係する外部サイト

実行環境に合わせたパラメータ設定方法

  • ps1ファイル内の、以下の変数を実行環境に合わせて書き換えてください。
  $FromPath = "バックアップ対象フォルダのパス名"  
  $DestPath = "バックアップ先フォルダのパス名" ※末尾には\を付けてください  
  $TranscriptPath = "実行ログの出力先パス名"   ※ファイル名を含む完全パス名
[バックアップ対象フォルダ]
$FromPath = "バックアップ対象フォルダのパス名"  

[バックアップ先フォルダ(世代フォルダの作成先)]
$DestPath = "バックアップ先フォルダのパス名\"  
[例]
$FromPath  = "C:\Folder1"              
$DestPath  = "C:\Folder1_backup\" 
 
実行時、[$DestPath+日付時刻文字列]でバックアップ先フォルダが作成されます。
 (例えば 2022年3月5日14時01分02秒に実行した場合)
  $DestPath  ="C:\Folder1_backup\20220304_140102\" フォルダ内にバックアップが作成されます。

[実行ログの出力先パス名]
$TranscriptPath = "フルパス"
[例]
# $TranscriptPath = "C:\Folder1\backup_xcopy_datetime.log"

サンプルコードの環境例

  • サンプルコードは、以下のフォルダ階層を想定したものとなっています。
[バックアップ対象のフォルダ]
C:\FOLDER1

[バックアップ世代フォルダ内に作成される世代フォルダ]
C:\FOLDER1_BACKUP
└[yyyyMMdd-HHmmss]フォルダ ※世代数分が保持されます。
  • バックアップ世代数を5世代とした場合、以下の例のようにバックアップ先フォルダ内には、常に直近の5世代分(5フォルダ)が維持されます。
  • 以下の状態から新たに当スクリプトを実行すると、新たに[yyyyMMdd-HHmmss]フォルダ(実行した日時分秒のフォルダ)が作成され、新たに保持すべき世代数としてカウンタとされます。そのため[20220306-101721]フォルダは6世代目となり保持対象を超え、フォルダごと削除されます。
[バックアップ世代フォルダ内に作成される世代フォルダ]
C:\FOLDER1_BACKUP
├─20220306-101721
├─20220306-101755
├─20220306-101820
├─20220306-101905
└─20220306-101931

実行ログのサンプル

  • PowerShellのトランスクリプトにより、以下のようなログファイルが出力されます。
  • 実環境において、ログファイルから読み取れる大切な内容は以下のとおりです。
    • XCOPYコマンドの終了コードと、その説明(Microsoftが公開しているxcopyコマンドの戻り値の説明文です。)
    • 各バックアップ世代フォルダの削除と維持の状態

**********************
Windows PowerShell トランスクリプト開始
**********************
トランスクリプトが開始されました。出力ファイル: C:\backup_xcopy_datetime.log
.
FromPath  = C:\Folder1
DestPath2 = C:\Folder1_backup\20220306-101308\
.


    ディレクトリ: C:\Folder1_backup


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        2022/03/06     10:13                20220306-101308
.
XCOPYコマンドを開始します
.

.
XCOPYコマンドが終了しました
.
xcopy終了コード=0:ファイルはエラーなしでコピーされました。
.
バックアップ世代管理の処理を開始
.
バックアップ先ベースフォルダ名:C:\Folder1_backup\
 バックアップのサブフォルダの総数:6
 保持する世代数:5
 削除されるフォルダ数:1
1 : 古いバックアップ世代のため削除 : 20220306-101004
2 : 保持対象:20220306-101006
3 : 保持対象:20220306-101146
4 : 保持対象:20220306-101220
5 : 保持対象:20220306-101242
6 : 保持対象:20220306-101308
.
バックアップ世代管理の処理が終了しました
.
**********************
Windows PowerShell トランスクリプト終了
**********************

ソースコード

# --------------------------------------------------------------------------------------------------------------------
# $FromPath = "バックアップ対象フォルダのパス名"  
# $DestPath = "バックアップ先フォルダのパス名\"  
# [例]
# $FromPath  = "C:\Folder1"              ※末尾には\を付けないでください。
# $DestPath  = "C:\Folder1_backup"  ※末尾に\を付けてください。
# 
# 実行時、[$DestPath+日付時刻文字列]でバックアップ先フォルダが作成されます。
# (例えば 2022年3月5日14時01分02秒に実行した場合)
#  $DestPath  ="C:\Folder1_backup\20220304_140102\" フォルダ内にバックアップが作成されます。
# --------------------------------------------------------------------------------------------------------------------
# ▼ 実行環境に合わせて書き換えてください。
$FromPath = "C:\Folder1"
$DestPath = "C:\Folder1_backup\" 
$BackupHistoryCount = 5



# --------------------------------------------------------------------------------------------------------------------
# $TranscriptPath       = "D:\バックアップXCOPY\backup_xcopy_datetime.log"
# ログファイルの出力先パス名を指定してください。
# --------------------------------------------------------------------------------------------------------------------
# ▼ 実行環境に合わせて書き換えてください。
$TranscriptPath       = "C:\Folder1\Xcopy_with_HistoryManagement.log"


# --------------------------------------------------------------------------------------------------------------------
# 以下は実行コードです。変更しないでください。  
# --------------------------------------------------------------------------------------------------------------------
# PowerShellログ出力の開始
Start-Transcript $TranscriptPath

# 日時分秒別のパスを作成
$ymdhms=Get-Date -Format "yyyyMMdd-HHmmss"
$DestPath2 = $DestPath + $ymdhms  + "\"

ECHO .
ECHO "FromPath  = $FromPath"
ECHO "DestPath2 = $DestPath2"
ECHO .

# バックアップ先フォルダを作成
New-Item ( $DestPath2 ) -ItemType Directory

ECHO .
ECHO "XCOPYコマンドを開始します"
ECHO .

XCOPY $FromPath $DestPath2 /S /Y /E /C /H 

# エラー検査
$XcopyExitCode=$LastExitCode

ECHO .
ECHO "XCOPYコマンドが終了しました"
ECHO .

if( ( $XcopyExitCode ) -eq 0 ) { ECHO xcopy終了コード=0:ファイルはエラーなしでコピーされました。               }
if( ( $XcopyExitCode ) -eq 1 ) { ECHO xcopy終了コード=1:コピーするファイルが見つかりませんでした。             }
if( ( $XcopyExitCode ) -eq 2 ) { ECHO xcopy終了コード=2:ユーザーが Ctrl + C キーを押して xcopy を終了しました。}
if( ( $XcopyExitCode ) -eq 4 ) { ECHO xcopy終了コード=4:初期化エラーが発生しました。 メモリまたはディスク領域が不足しているか、コマンド ラインに無効なドライブ名または無効な構文が入力されました。}
if( ( $XcopyExitCode ) -eq 5 ) { ECHO xcopy終了コード=5:ディスク書き込みエラーが発生しました。                 }


ECHO .
ECHO "バックアップ世代管理の処理を開始"
ECHO .

# バックアップ世代管理
[System.IO.DirectoryInfo[]] $DestPath_SubFolders = dir $DestPath  -Directory

$DestPath_SubFolders_Count         = $DestPath_SubFolders.Count
$DestPath_SubFolders_EraseCount = $DestPath_SubFolders.Count - $BackupHistoryCount

echo "バックアップ先ベースフォルダ名:$DestPath"
echo " バックアップのサブフォルダの総数:$DestPath_SubFolders_Count"
echo " 保持する世代数:$BackupHistoryCount"
echo " 削除されるフォルダ数:$DestPath_SubFolders_EraseCount"

$cnt = 0
foreach ($item in $DestPath_SubFolders) {
    $cnt = $cnt + 1
    if( ( $cnt -le $DestPath_SubFolders_EraseCount ) -eq "true"  ){ 
        ECHO "$cnt : 古いバックアップ世代のため削除 : $item"

        $eraseFullPath = $DestPath + $item
        Remove-Item -Path $eraseFullPath -Recurse -Force
    } else { 
        ECHO "$cnt : 保持対象:$item" 
    }
}

ECHO .
ECHO "バックアップ世代管理の処理が終了しました"
ECHO .

# PowerShellログ出力の終了
Stop-Transcript

小規模でのiPad運用とMDM(Mobile Device Management)のjamf Nowについて

*jamfNowの試用開始は、ここから行うことができます(iPadなど3デバイスまで無料です。)

signup.jamfnow.com

小規模でのiPad運用で起こりがちなこと

  • 営業等の社員へ配布することを目的に、数台のiPadApple Store 名古屋栄からオンライン購入した際の体験談です。

  • 導入台数が一定以上あれば、Apple Storeにて、Apple Business Manager(ABM) の導入を行って貰えるらしいのですが、購入台数が数台であるために、おこなって貰っていませんでした。

  • 運用経費を削減するめ、MVMOのSIMカードを別途調達。
  • 社内にはWindowsマシンしかありません。どうやって設定内容を、全てのIpadで揃えようか(キッディング作業)、試行錯誤する。
  • 試行錯誤を通じて、Ipadの仕様について理解を深めていく過程となりました。結局は、キッディングを1台づつ行なって対応しました。
  • ABMがない場合、個人向けAppleIDでの運用となってしまいます。その場合、プライバシー保護が重視されており、組織としての情報システム管理者による一元的な管理を行うことが難しい、という課題があることに気づきました。]
  • 経験を通じて理解を深めるだけの手間がかけられるならば、こうした手作業は決して無駄ばかりではありません。しかし、数量が多い場合や、運用開始後も含めて組織上の責任を伴うような場合には、何かと制約が多く、管理が社員任せになりがちでリスクを伴う印象があります。
  • こうしたことから、法人内でiPadを運用する場合、必然的に運用管理ツールが必要となるであろうことが想像されましたが、当時はそうした製品の有無まで調べる余裕はありませんでした。

解決策としてのMDM(Mobile Device Management)

  • 一般的には、MDM(Mobile Device Management)を導入することで、こうした課題への対策が行える。
  • 市場には幾つもMDMサービスがあり、iPadの用途に合うものを選ぶと良い。
  • MDMサービスの利用コストは、iPad導入とセットで考えておく方が良い。
  • 導入時点から既にMDMがあれば、キッディングが自動で行えるようになる。更新も自動で行われる。

jamf Nowとは?

  • jamf Now は、Apple製品向けのクラウドMDMサービス(Mobile Device Management)。上位製品には jamfPro がある。
  • 小規模でのApple製品の運用管理に向いており、IT専任担当者がいない組織でも活用しやすいとされている。
  • 3デバイスまでは無料で使うことが可能。それ以上は2ドル/1台/月。

    jamf Now Demoサイト

jamf Now を試用してみる

  • iPad管理なら、漠然と「jamf Pro」が良さそうとは考えていた。iPad導入台数が10台未満ということで、AppleStoreではAMBまでは用意してくれていなかった。
  • 2021年2月に、たまたま受講したWebセミナーで小規模運用向けに「jamf Now」がリリースされたことを知り、無料枠があることで、試してみたくなった。クラウドサービス全般に言えることだが、実際に使ってみないと分からないことが多い。無料枠があれば試用しやすい。
  • 利活用時にはIT専任担当者でなくても大丈夫とのことであるが、「jamf Now」を新規導入したり、「ABM」も自分で新規に導入する段階から行おうとすると、相応に知識やスキルが必要になる。むしろ、新しい知識を得るチャンスと考え、チャンレジしてみることにした。
  • なお、jamf社のWebサイトやYoutubeにも作業手順は掲載されており、その通りに進めればできそうではある。(ただし英文ばかり。)

www.jamf.com


Apple Business Manager(ABM)にアカウント作成

  • 少なくとも Apple Business Manager(ABM)にアカウント作成が必要です。

  • AMBアカウントを作成するには、法人を特定するための9桁の番号である「D-U-N-S Number」の入力が求められる。国内では、東京商工リサーチのWebサイトから、自社に割り当てられた番号があるか検索することができる(自社の番号については無料)。問い合わせ後、回答を得るまでに数日が必要となることも。 また、Apple社による審査もあり、最大5日程度掛かるとされているため、日程には余裕を見ておく方が良さそう。

    www.tsr-net.co.jp

iPadへの展開内容を定義するもの(BluePrint)

  • iPadへ展開したい設定内容をあらかじめ定義しておくことができます。
  • 例えば、営業向けの設定内容をまとめたBluePrintを作成します。
  • jamf Nowには、あらかじめBbluePrintのテンプレートがあり、それを流用加工することで、素早く作成することもできます。

既に運用されているiPadMDM配下にする(open enrollment)

  • 既に運用されているiPadMDM配下にする場合は Open enrollmentを使用します。
  • 全く新しいiPadを全て自動でキッディングする場合は、AutoEnrollmentを使用します。
  • 既に運用されているiPadに対してAutoEnrollmentを展開する場合は、既存の環境がすべて消去されるため、Open Enrollmentの方が推奨されます。

JupyterNoteBookからのPDF出力で日本語を表示可能にする(MikTexの設定)

  • 以下のサイトを参考にさせて頂きました。

ZXjatype パッケージ ~XeLaTeX でまともな日本語組版を~

Windowsに「IPAフォント」をインストール

「zxjatype」パッケージのインストール

  • MikTexコンソールから、「zxjatype」パッケージをインストールします

f:id:persimoon:20210120152515j:plain

(Jupyter Notebook側)デフォルトのLatext定義ファイルの編集

  • Jupyter Notebook からPDF出力する際に、既定値として使用される Latext定義ファイルに相当するもの(documentclassを定義しているもの)が存在している筈です。
  • 該当するファイルを検索するために、VSCode等でキーワード「documentclass」を検索します。
    VSCodeの場合:Open Folderで仮想環境パスを開いた後、ctrl+shift+Uキー、キーワードを入力してください。)

  • 筆者の環境の場合、デフォルトのLatext定義ファイルの保存場所は、以下の通りでした。
    (使用している仮想環境名は「test1」です)
    「C:\Anaconda_Datas\envs\test1\share\jupyter\nbconvert\templates\latex\index.tex.j2
(仮想環境パス)\share\jupyter\nbconvert\templates\latex\index.tex.j2
  • 以下のような内容になっています。(Latex Article の部分が対象になります。)
[index.tex.j2] ※編集前

((=- Default to the notebook output style -=))
((*- if not cell_style is defined -*))
    ((* set cell_style = 'style_jupyter.tex.j2' *))
((*- endif -*))

((=- Inherit from the specified cell style. -=))
((* extends cell_style *))


%===============================================================================
% Latex Article
%===============================================================================

((*- block docclass -*))
\documentclass[11pt]{article}
((*- endblock docclass -*))

  • これを、以下のように書き換えます。(ファイルを書き換える前に、必ずバックアップを取っておいてください。) エンコードは「UTF-8」から変更しないようにしてください。
[index.tex.j2] ※編集後

((=- Default to the notebook output style -=))
((*- if not cell_style is defined -*))
    ((* set cell_style = 'style_jupyter.tex.j2' *))
((*- endif -*))

((=- Inherit from the specified cell style. -=))
((* extends cell_style *))


%===============================================================================
% Latex Article
%===============================================================================

((*- block docclass -*))
\documentclass[a4paper]{bxjsarticle}
\usepackage{fontspec}
\usepackage{zxjatype}
\setjamainfont{ipam.ttf}
\setjasansfont{ipag.ttf}
\setjamonofont{ipag.ttf}
\usepackage{xltxtra}
((*- endblock docclass -*))

日本語が表示されるようになりました。

  • 定義ファイルを編集する以前は、日本語の部分が表記されずにスキップされていましたが、編集後は、きちんとコメント行の欠落が解消されています。
[編集前]
# Python (欠落部分) datetime (欠落部分) 

[編集後]
# Pythonデータ型は自動でdatetime型に変換されます

左:編集前 右:編集後(日本語表示あり)

外部リンク

IPAフォント

Texパッケージ

JupyterNoteBookからPDFファイルに出力可能にする(MikTexインストール)

  • JupitorNoteBookにはPDFファイルとして保存するメニュー( Download as PDF via LaTeX )がありますが、Windows組版処理ソフトウェアである「xelatex」がインストールされていない状態では、サーバエラー(500)が発生します。 ここでは、MikTexのインストール方法について触れます。

f:id:persimoon:20210105160218j:plain

f:id:persimoon:20210105155510j:plain

miktexのダウンロードとインストール

f:id:persimoon:20210120134226j:plain

f:id:persimoon:20210120134327j:plain

[コマンドプロンプト]

C:\Users\user01>xelatex.exe
This is XeTeX, Version 3.14159265-2.6-0.999992 (MiKTeX 20.12)
**
  • jupyter notebookから、PDFファイルとして保存するメニュー( Download as PDF via LaTeX )を実行します。
  • XeLaTexを初めて実行した場合、不足する各種パッケージを自動的にインストールするため、「Package Installation」ダイアログが表示される場合があります。「Always show this dialog ...」のチェックを外してからInstallをクリックしましょう。(チェックを外さないと、必要なパッケージ数だけ同様のダイアログ画面が何度も表示されることになります。)

f:id:persimoon:20210120141600j:plain

  • 「MikTex Console」を起動し、インストールされた「Package」を確認することができます。

f:id:persimoon:20210120143333j:plain

  • PDF出力できるようになりましたが、日本語のコメント部分が表示されていません。
    XeLaTexで日本語を表示できるようにする方法は、別ページで触れたいと思います。まずはPDF出力が可能となったたので、当ページはここまでで良しとします。

f:id:persimoon:20210120142621j:plain

batファイルからpythonコードを実行する方法

batファイル化する目的とメリット

  • Windowsのbatファイルから、直接pythonコードを実行できると、とても便利です。
  • 一般に、batファイル化することでWindowsサーバのタスクスケジューラからpythonコードを繰り返し実行でき、データ処理を自動化できるようになります。
  • このサンプルでは、openpyxlを用いて、サーバサイドでExcelファイル出力を自動化します。

Windows batファイルの役割

  • batファイルから行いたいことは、以下の通りです。
    • 特定のAnaconda仮想環境を有効化(Activate)
    • pythonコ-ドを実行

以下のサンプル例の前提条件

  • 仮想環境[test1]が作成済み。
  • openpyxlがinstall済み。

pythonコ-ドを作成します

  • 「test1.py」を作成します(以下のコード)。Excelファイルを作成するサンプルコードが含まれています。
  • なお、Windowsのbatファイルにて「CDコマンド」で指定した「カレントディレクトリ」は、pythonコードに対しては有効ではありませんので、pythonコード中で
    「os.chdirコマンド」を使用して 実行中のpythonコードでの「カレントディレクトリ」を指定しています。
  • openpyxl ライブラリを使用してExcelファイルを作成します。
[test1.py]

import os

from openpyxl import Workbook
import datetime

os.chdir('C:\Anaconda_Datas')

now = datetime.datetime.now()
print ('# python code started : '+ now.strftime("%m/%d/%Y, %H:%M:%S"))

# Excel WorkBook
wb = Workbook()

# grab the active worksheet
ws = wb.active

# セルに直接データを配置することができます
ws['A1'] = 42

# 行にも配置できます
ws.append([1, 2, 3])

# Pythonデータ型は自動でdatetime型に変換されます
ws['A2'] = datetime.datetime.now()

# Excelファイルを保存します(os.chdirコマンドで指定したカレントディレクトリに保存されます。)
wb.save("sample.xlsx")

now = datetime.datetime.now()
print ('# python code End     : '+ now.strftime("%m/%d/%Y, %H:%M:%S"))

Windowsバッチファイルを作成

  • batファイルには、以下のように記述します。
  • batファイルを呼び出しているWindowsコマンドプロンプトは直ぐに閉じてしまうため、pythonコードがちゃんと実行されたかどうか分かり難いので、[>> activate_test1.log]として、出力をテキストファイルに保存しています。
[activate_test1.bat]

CD /D C:\Anaconda_Datas                                             

REM 仮想環境を有効化します
CALL C:\Anaconda_Datas\envs\test1\Lib\venv\scripts\nt\activate.bat     >> activate_test1.log

REM Pythonコ-ドを実行します
C:\ProgramData\Anaconda3\python.exe C:\Anaconda_Datas\test1.py         >> activate_test1.log

REM 仮想環境を無効化します
CALL C:\Anaconda_Datas\envs\test1\Lib\venv\scripts\nt\deactivate.bat   >> activate_test1.log

batファイルを実行

  • Windowsコマンドプロンプトからbatファイルを実行します。
  • batファイルが正常に実行されると、"sample.xlsx"と"activate_test1.log"が作成されます。

f:id:persimoon:20210103180010j:plain

  • [activate_test1.log]には、以下のように出力されました。
[activate_test1.log]

# python code started : 01/03/2021, 17:53:32
# python code End     : 01/03/2021, 17:53:33