PowerShellのスクリプトをタスクスケジューラで実行させる
環境:Windows 10 Pro
PowerShellスクリプトのパス:C:\Task\HogeHoge.ps1
新しい操作で設定する項目は次のようにする。
プログラム/スクリプト:C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
引数の追加:-ExecutionPolicy Bypass "C:\Task\HogeHoge.ps1"
開始:C:\Task
*スクリプトで絶対パスを指定しているのであれば開始のパスは無くて良い。
-ExecutionPolicy Bypass
を指定しないと権限がない!とかで実行してくれない。
バッチファイルやPowerShellでSQL ServerのデータをCSV出力する
SQL Server 2017のデータを定期的(タスクスケジューラ等で)にCSV(タブ区切り)のShift-JISで出力したい。
*SQLiteに取り込みたいのでヘッダーは"なし"にしている。
バッチファイル (sqlcmdを使用)
sample1.bat
@echo off set db_server=HogeSql set db_database=HogeDb set db_user=sa set db_password=PassW0rd set db_param='りんご' sqlcmd -S %db_server% -U %db_user% -P %db_password% -d %db_database% -i .\sample1.sql -v Param1=%db_param% -b -s"<tab>" -h -1 -W -o .\sample1.csv
<tab>
と書いている箇所には、タブ記号(タブキー)を入力すること
sample1.sql
SET NOCOUNT ON SELECT * FROM ITEM_TBL WHERE ITEM_NAME = $(Param1) SET NOCOUNT OFF
SET NOCOUNT ON
、SET NOCOUNT OFF
を記入しないと"(1 行処理されました)"等のメッセージも出力される。
$(Param1)
に代入されている値には、' (シングルクォーテーション)
の記号も含まれる。
PowerShell (Invoke-Sqlcmdを使用) その1
sample2.ps1
$db_server = "HogeSql" $db_database = "HogeDb" $db_user = "sa" $db_password = "PassW0rd" $db_params = @("Param1='りんご'") $ret = Invoke-Sqlcmd -InputFile ".\sample2.sql" -Variable $db_params -ServerInstance $db_server -Database $db_database -Username $db_user -Password $db_password | ConvertTo-Csv -Delimiter "`t" -NoTypeInformation $ret | Select-Object -Skip 1 | % {$_ -replace '"', ""} | Out-File (".\sample2.csv") -Force -Encoding oem
1行目にヘッダーがあり、データも" (ダブルクオーテーション)
で囲まれているので、それらを削除している。
出力フォーマットはShift-JISにする。
sample2.sql
SELECT * FROM ITEM_TBL WHERE ITEM_NAME = $(Param1)
SET NOCOUNT ON
、SET NOCOUNT OFF
は必要でない。
PowerShell (Invoke-Sqlcmdを使用) その2
sample3.ps1
$db_server = "HogeSql" $db_database = "HogeDb" $db_user = "sa" $db_password = "PassW0rd" $db_params = @("Param1='りんご'") $sql_command = "SELECT * FROM ITEM_TBL WHERE ITEM_NAME = `$(Param1)" $ret = Invoke-Sqlcmd -Query $sql_command -Variable $db_params -ServerInstance $db_server -Database $db_database -Username $db_user -Password $db_password | ConvertTo-Csv -Delimiter "`t" -NoTypeInformation $ret | Select-Object -Skip 1 | % {$_ -replace '"', ""} | Out-File (".\sample3.csv") -Force -Encoding oem
SQLのスクリプトファイルは使用せず、直接SQLを書いている。
このとき、SQLの変数`$(Param1)
の"$"の前には` (バッククォート)
を付加すること。
そうしないとPowerShellの変数として扱われ展開されるので。
参考URL
powershell - Invoke-sqlcmd output without "quotes" and headers - Stack Overflow
SQL ServerでDBの復元に失敗する
バックアップしたDBを別のパソコンに復元しようとしたら次のエラーが発生して失敗した。
DBの互換性レベルは、SQL Server 2017(140)にしている。
- バックアップ元は、SQL Server 2019
- 復元先は、SQL Server 2017
System.Data.SqlClient.SqlError: データベースはバージョン 15.00.2000 を実行中のサーバーにバックアップされました。このバージョンは、このサーバー (バージョン 14.00.3192 を実行) とは互換性がありません。バックアップをサポートしているサーバーでデータベースを復元するか、またはこのサーバーと互換性のあるバックアップを使用してください。 (Microsoft.SqlServer.SmoExtended)
どうもSQL Serverのバージョンが違うと復元できないようです。
バージョン違いのバックアップしたDBを復元をするには、同じバージョンのSQL Serverをインストールするしかないっぽい。
DBの復元手順
仮想環境を立ち上げて、SQL Serverをインストールする。
SSMSからDBを復元して、復元したDBを選択して右クリックからの[タスク]-[スクリプトの生成]を実行する。
"特定のデータベース オブジェクトを選択"からテーブルを選択する。
スクリプトは"ファイルに保存"を選択して"単一ファイル"に出力する。
SQL Server 2019から
OPTIMIZE_FOR_SEQUENTIAL_KEY
というコマンドが追加されており、このままではSQL Server 2017で使用できないので出力したスクリプトファイルからOPTIMIZE_FOR_SEQUENTIAL_KEY
を削除した。
開発環境側で同じDB名を作成しておき、このスクリプトを実行してテーブルを作成する。
exp_table.bat, exp_table.vbsを用意し、仮想環境側でexp_table.batを実行する。
直下にexp_impフォルダが作成され、フォルダの中のrun_exp.bat
を実行する。
exp_imp\dataフォルダにエクスポートしたデータが出力される。
exp_impフォルダごと開発環境にコピーして、exp_impフォルダの中のrun_imp.bat
を実行する。
参考URL 【SQL Server】bcpを使用したインポートとエクスポート - 小物SEのメモ帳
exp_table.bat
CScript .\exp_table.vbs
exp_table.vbs
Dim FROM_DB_SERVER Dim FROM_DB_NAME Dim FROM_DB_USER Dim FROM_DB_PASSWORD Dim TO_DB_SERVER Dim TO_DB_NAME Dim TO_DB_USER Dim TO_DB_PASSWORD Dim strRootPath '========== 'DB接続情報(バックアップ元) FROM_DB_SERVER = "PC-A\HOGE_SQL" FROM_DB_NAME = "HOGE_DB" FROM_DB_USER = "sa" FROM_DB_PASSWORD = "P@ssw0rd" 'DB接続情報(復元先) TO_DB_SERVER = "PC-B\DEV_SQL" TO_DB_NAME = "HOGE_DB" TO_DB_USER = "sa" TO_DB_PASSWORD = "P@ssw0rd" '========== 'データ出力先 strRootPath = GetFolderPath() Call CreateFolder(strRootPath & "\exp_imp") Call CreateFolder(strRootPath & "\exp_imp\data") 'batファイルを作成(run_exp.bat, run_imp.bat) Call CreateBatchFile WScript.Quit Sub CreateBatchFile() Dim adoConn Dim adoComm Dim adoRS Dim objFso Dim expTs Dim impTs Dim strBuff Set adoConn = CreateObject("ADODB.Connection") Dim strConnect strConnect = "Provider=SQLOLEDB;" & _ "Data Source=" & FROM_DB_SERVER & ";" & _ "Initial Catalog=" & FROM_DB_NAME & ";" & _ "User ID=" & FROM_DB_USER & ";" & _ "Password=" & FROM_DB_PASSWORD adoConn.ConnectionString = strConnect adoConn.Open Set adoComm = CreateObject("ADODB.Command") adoComm.ActiveConnection = adoConn adoComm.CommandTimeout = 0 adoComm.CommandType = 1 Set objFso = CreateObject("Scripting.FileSystemObject") adoComm.CommandText = "SELECT name AS TABLE_NAME FROM sys.tables" Set adoRS = adoComm.Execute If adoRS.EOF = False Then Set expTs = objFso.CreateTextFile(strRootPath & "\exp_imp\" & "run_exp.bat") Set impTs = objFso.CreateTextFile(strRootPath & "\exp_imp\" & "run_imp.bat") Dim strTableName Do While Not adoRS.EOF strTableName = adoRS("TABLE_NAME").Value 'run_exp.bat フォーマット strBuff = "bcp " & strTableName & " format nul -c -x -f .\data\" & strTableName & "_fmt.xml -t, -S " & FROM_DB_SERVER & " -U " & FROM_DB_USER & " -P " & FROM_DB_PASSWORD & " -d " & FROM_DB_NAME expTs.WriteLine (strBuff) 'run_exp.bat データCSV strBuff = "bcp " & strTableName & " out .\data\" & strTableName & ".csv -S " & FROM_DB_SERVER & " -U " & FROM_DB_USER & " -P " & FROM_DB_PASSWORD & " -d " & FROM_DB_NAME & " -f .\data\" & strTableName & "_fmt.xml -t, -o .\data\" & strTableName & "_output.log" expTs.WriteLine (strBuff) 'run_imp.bat データCSV strBuff = "bcp " & strTableName & " in .\data\" & strTableName & ".csv -S " & TO_DB_SERVER & " -U " & TO_DB_USER & " -P " & TO_DB_PASSWORD & " -d " & TO_DB_NAME & " -f .\data\" & strTableName & "_fmt.xml -t, -o .\data\" & strTableName & "_input.log" impTs.WriteLine (strBuff) adoRS.MoveNext Loop expTs.Close Set expTs = Nothing impTs.Close Set impTs = Nothing adoRS.Close Set adoRS = Nothing End If Set objFso = Nothing Set adoComm = Nothing adoConn.Close Set adoConn = Nothing End Sub Function GetFolderPath() Dim objFso Set objFso = CreateObject("Scripting.FileSystemObject") GetFolderPath = objFso.GetParentFolderName(WScript.ScriptFullName) Set objFso = Nothing End Function Sub CreateFolder(strFolder) Dim objFso Set objFso = CreateObject("Scripting.FileSystemObject") If objFso.FolderExists(strFolder) = False Then Call objFso.CreateFolder(strFolder) End If Set objFso = Nothing End Sub
ログファイルを削除するためのスクリプト(VBS)
ログファイルを定期的に削除したい。
専用アプリを作成してまで削除するのもどうかと思ったのでスクリプト(VBScript)で実行することにした。
ログファイルの削除は、ファイル名に日付が入っているので、ファイル名の日付で削除する。
実行は、タスクスケジューラを使用する。
VBSのまま、タスクスケジューラに登録しても実行されないので、batファイルからVBSを実行するようにする。
DELETE_TASK.bat
CScript C:\HOGE_HOGE\TASK\DELETE_FILE.vbs
DELETE_FILE.vbs
Dim targetPath '削除対象のフォルダ targetPath = "C:\HOGE_HOGE\LOG\" '3年前のファイルを削除する Call DeleteFile(targetPath, 3) WScript.Quit 'ログ用フォルダにhoge_yyyymmdd.logのファイルがある Sub DeleteFile(folderPath, deleteYear) Dim fso Dim files Dim file Dim deleteDate Dim temp Set fso = CreateObject("Scripting.FileSystemObject") Set files = fso.GetFolder(folderPath).Files 'n年前のファイルを削除する deleteDate = DateAdd("yyyy", -deleteYear, Date) 'フォルダ内のファイルを列挙 For Each file In files '拡張子がlogファイルのみを削除対象とする If Right(file.Name, 4) = ".log" Then '"hoge_yyyymmdd.log"を"yyyy-mm-dd"の書式に変換 temp = Mid(file.Name, 6, 8) temp = Left(temp, 4) & "-" & Mid(temp, 5, 2) & "-" & Right(temp, 2) If IsDate(temp) = True Then If CDate(temp) < deleteDate Then file.Delete(True) End If End If End If Next Set file = Nothing Set files = Nothing Set fso = Nothing End Sub '日付(yyyymm)フォルダが作成され、そのフォルダ内にログファイルがある '日付フォルダごと削除する Sub DeleteFile2(folderPath, deleteYear) Dim fso Dim folders Dim folder Dim deleteDate Dim temp Set fso = CreateObject("Scripting.FileSystemObject") Set folders = fso.GetFolder(folderPath).SubFolders 'n年前のファイルを削除する deleteDate = DateAdd("yyyy", -deleteYear, Date) 'フォルダ内のフォルダを列挙 For Each folder In folders '"yyyymm"を"yyyy-mm-dd"の書式に変換 temp = Left(folder.Name, 4) & "-" & Right(folder.Name, 2) & "-01" If IsDate(temp) = True Then If CDate(temp) < deleteDate Then folder.Delete(True) End If End If Next Set folder = Nothing Set folders = Nothing Set fso = Nothing End Sub
波線を描画したい(VB.net)
波線を描画したくなった。
作成はVisual Basic 2017で行った。
DrawLineを使って描いても良かったんだけど、もう少し効率の良い方法はないかと探してみて色々試した結果、DrawCurveを使うことにした。
等間隔で中央、上、中央、下、中央…という感じでy位置を変化させてPointに格納しDrawCurveで曲線を描画させた。
横線のみです。
Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint Dim canvas As New Bitmap(PictureBox1.Width, PictureBox1.Height) Dim g As Graphics = Graphics.FromImage(canvas) DrawWavyLine(g, Pens.Blue, 0, 200, 200) PictureBox1.Image = canvas End Sub '横の波線を描画 Public Sub DrawWavyLine(ByRef g As Graphics, ByRef pen As Pen, ByVal x1 As Single, ByVal y1 As Single, ByVal x2 As Single) '-------------------- '波線の設定 '-------------------- '波線の曲線(0.0 = 直線 ~ 1.0 = 曲線) Dim tension As Single = 1.0F '波線の幅 Dim waveWidth As Single = 5.0F '波線の高さ Dim waveHeight As Single = 5.0F '-------------------- Dim points As New List(Of PointF) Dim x As Single = 0F Dim y As Single = 0F Dim f As Integer = 0 While x < (x2 - x1) Select Case f Case 0, 2 y = 0F Case 1 y = -waveHeight Case 3 y = waveHeight End Select f = If(f < 3, f + 1, 0) points.Add(New PointF(x, y1 + y)) x += waveWidth / 2.0F End While g.DrawCurve(pen, points.ToArray(), tension) End Sub
斜めの波線の途中未完成!!
- 横線を引き、そこに等間隔で縦線を引く
- その横線を傾けたときの角度を求める
- 縦線の上、中央、下の位置に対して角度を適応した位置を求める
- 中央、上、中央、下、中央…の位置をPointに格納してDrawCurveに投げると…なんか上手くいかない!
Public Sub DrawWavyLine2(ByRef g As Graphics, ByRef pen As Pen, ByVal x1 As Single, ByVal y1 As Single, ByVal x2 As Single, ByVal y2 As Single) '-------------------- '波線の設定 '-------------------- '波線の曲線(0.0 = 直線 ~ 1.0 = 曲線) Dim tension As Single = 0.0F '波線の幅 Dim waveWidth As Single = 10.0F '波線の高さ Dim waveHeight As Single = 10.0F '-------------------- Dim points As New List(Of PointF) Dim x As Single = 0F Dim y As Single = 0F Dim f As Integer = 0 Dim wx1 As Single = 0F Dim wy1 As Single = 0F Dim wx2 As Single = 0F Dim wy2 As Single = 0F Dim wx3 As Single = 0F Dim wy3 As Single = 0F '2点間の角度 Dim radian As Double = Math.Atan2(y2 - y1, x2 - x1) Dim cos As Double = Math.Cos(radian) Dim sin As Double = Math.Sin(radian) While (x1 + x) < x2 '角度から座標を求める wx1 = x * cos - -waveHeight * sin wy1 = x * sin + -waveHeight * cos wx3 = x * cos - 0F * sin wy3 = x * sin + 0F * cos wx2 = x * cos - waveHeight * sin wy2 = x * sin + waveHeight * cos Select Case f Case 0, 2 y = wy3 Case 1 y = wy1 Case 3 y = wy2 End Select f = If(f < 3, f + 1, 0) points.Add(New PointF(x1 + x, y1 + y)) x += waveWidth / 2.0F End While g.DrawCurve(pen, points.ToArray(), tension) End Sub
参考URL
開発メモ:円周上の点
2点間の距離と角度と座標の求め方
Windows 10 BitLockerを無効にする
Windows 10 のパソコンのバックアップをAcronis True Imageで取ろうとしたけど「BitLockerが有効のためバックアップできない」と言われた。
BitLockerを無効にするためにコントローラパネルから"BitLocker ドライブ暗号化"を開くと「Windows (C:) BitLocker はアクティブ化を待機中です」と表示されており、BitLockerを無効にするが選べなかった。
調べてみると[スタート]-[設定]-[更新とセキュリティ]を開く。
左側の一番下にある「デバイスの暗号化」を開き"オフにする"を押すと出来るみたいだけど[更新とセキュリティ]にあるはずの「デバイスの暗号化」が見つからない!
色々試してみると、サービスの「BitLocker Drive Encryption Service」を無効にしていると「デバイスの暗号化」が表示されないみたい。
このサービスを手動にして開始すると「デバイスの暗号化」が表示されて無事にBitLockerを無効にすることが出来た。
Webカメラのかわりにスマホ(iVCam)を使う
テレワークをすることになったけど、Webカメラが売ってない。
色々検索してみるとスマートフォンをWebカメラがわりにすることが出来る情報を得たので早速ためしてみたときのメモ。
参考URL
Webカメラが品切れでもOK? スマホをWebカメラとして使える「iVCam」を試してみた
E2ESOFT iVCam
使用するスマートフォンは、HUAWEI P20 lite
パソコンは、Windows 10 Professional
Webカメラのアプリは、iVCam
インストールも簡単に終わり、スマートフォンをWebカメラのかわりにできた。
パソコンにはマイクが付いており、スマホの方でも音声をひろっていたのでスマホ側の設定を変更し音声を無効にした。