starzware

ITスキル

PowerShell

TIPS
コマンド
コマンド 説明
Write-Output コンソール(またはPowerShell ISE)に出力
Set-Location ディレクトリのパスを指定し、ディレクトリを移動する
New-Item ファイル、フォルダの新規作成[Alias]ni
Remove-Item 削除(del,rm,rmdirに似た機能)、レジストリ削除
Get-Content ファイル内容(テキスト)を表示(type,catに似た機能)
Invoke-Item 色々実行(フォルダを開く、関連づけて開く、実行ファイル実行...)
Select-String ファイルから文字列を検索する(findstr,grepに似た機能)
Get-ChildItem ディレクトリ情報を取得
Test-Path パスのすべての要素が存在するかどうかを確認
Get-Counter システムのパフォーマンスを計測
Get-EventLog Windows のイベントログを取得
Write-EventLog Windows のイベントをログに記録
New-EventLog 新しいイベントソースを作成
ConvertTo-Json オブジェクトを JSON 形式の文字列に変換
ConvertTo-Xml オブジェクトの XML ベースの表現を作成
Compress-Archive ZIP圧縮
Expand-Archive ZIP解凍
New-Object Microsoft .NET Framework または COM オブジェクトのインスタンスを作成
VBScriptで言えばCreateObject
Get-NetAdapter コンピュータのネットアダプタを取得する
New-NetIPAddress ネットアダプタに静的IPアドレスを設定する
Get-NetTCPConnection TCPポートのコネクションを確認する
Test-NetConnection ネットワークの疎通を確認する
Get-NetIPConfiiguration ネットワークアダプタのIP設定を取得する
New-NetRoute ネットワークの経路を設定する
Get-DNSClientCashe リゾルバキャッシュを取得する
Get-NetNeighbor ネットワークアダプタのARPテーブルを取得
Get-NetConnectionProfile ネットワーク状態を取得する
Get-NetAdpterAdvancedProperty ネットワークアダプターの詳細設定を取得する
Start-Process
CheckPoint-VM [Hyper-V]チェックポイントを作成する
スクリプト実行設定

# ローカルで作成されたスクリプトは無条件で実行できるが、ネットワークから入手したスクリプトは署名が無ければ実行できない
Set-ExecutionPolicy RemoteSigned

# batで起動する例
powershell -NoProfile -ExecutionPolicy Bypass hogehoge.ps1
# batで起動する例2
powershell -ExecutionPolicy RemoteSigned コマンド
スクリプトの文字コードと改行

[文字コード] *BOM付きUTF-8がベターかも
SJIS、BOM付きUTF-8、UTF-16
[改行コード]
CR/LF(¥r¥n) *LFだけだと誤動作する
エスケープシーケンス

エスケープシーケンス
バッククォート(`)を使用する
タブ `t
改行 `r `n
ダブルクォーテーション `"
引数

# ./hogehoge.ps1 -filename xxxx -count xxx を定義(countはデフォルト=100)
param (
  [string]$filename,
  [int]$count = 100
)
自動変数
自動変数 説明
$true true
$false false
$null NULL
$$ 最後に実行したステートメント
$? 最後に実行したステートメントの結果(コマンドレットの結果)
$LASTEXITCODE 最後に実行した外部コマンドの結果(コマンドレットの結果ではない)
$PSScriptRoot スクリプト自身のパスを表す
$IsWindows 環境がWindowsか
IsLinux 環境がLinuxか
IsMacOS 環境がMacOSか
出力(Write-Output)

### 単にコンソールに出力するならWrite-Hostでよい。
# コンソール(またはPowerShell ISE)に出力
Write-Output "Hello World in PowerShell!" | Out-Host
# デフォルトに出力
Write-Output "Hello World in PowerShell!" | Out-Default
# 最後に出力された先かデフォルトに出力
Write-Output "Hello World in PowerShell!"

Out-File, Out-GridView,Out-Null,Out-Printer,Out-String
Excel

$excel = New-Object -ComObject Excel.Application
$book = $excel.Workbooks.Open("C:\hogehoge.xlsx")

# シートの取得
$sheet = $book.Worksheets.Item("Sheet1")

# セル値の取得
$cell_value = $sheet.Cells.Item(1, 2).Value()
$cell_value = $sheet.Range("B2").Value()
# セル数式の取得
$cell_formula_value = $sheet.Cells.Item(1, 2).Formula()
$cell_formula_value = $sheet.Range("B2").Formula()

# 使用している行数
$sheet.UsedRange.Rows.Count
# 使用している列数
$sheet.UsedRange.Columns.Count

# セルに値を設定
$sheet.Cells.Item(1, 2).Value() = $cell_value

# シートループ
foreach ( $sheet2 in $excel.Worksheets ) {
  $sheetname = $sheet2.Name
}

# テキストボックス(オートシェイプ)からテキストを取得
for ($idx=1; $idx -le $sheet.Shapes.Count; $idx++){
  # Shapes("名称")でも取得できるはず
  $text = $sheet.Shapes($idx).TextFrame().Characters().Text
}
# テキストボックスを追加
$sheet.Shapes.AddTextbox(1(msoTextOrientationHorizontal), left, top, width, height).TextFrame().Characters().Text = "テキストボックスに表示"

# 上書きセーブ
[void]$book.Save()
# Bookをとじる
[void]$book.Close($false)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($book)
# Excelの終了
[void]$excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)
ZIP圧縮

# 圧縮
Compress-Archive -Path 圧縮する対象 -DestinationPath ZIPファイル
パス結合とフルパス

# パス結合 セパレータは自動判別で付与される
$allPath = Join-Path "C:¥" "hogehoge" "filename.ext"
"C:¥hogehoge¥filename.ext"
# フルパス
$path = ".¥filename.ext"
$fullPath = Convert-Path $path
親フォルダを取得する

Split-Path -Path $path
ファイル名取得(.NET版)

$path = "root/path/file.ext"
$filename = [System.IO.Path]::GetFileName($path)
POST

# 
Invoke-RestMethod -Method Post -Uri http://localhost:8080/aaaa -Headers @{'xxx' = 'xxx'} -Body '{"xxx":"xxx"}'

# 
$createUrl = "$baseUrl/Server/api-001"
$body = @{
    item = "TEST-001"
    name = "Test from PowerShell"
} | ConvertTo-Json
$response = Invoke-RestMethod -Uri $createUrl -Method Post -Headers $headers -Body $body

インポート

# スクリプト自身と同じフォルダのenv.ps1を読み込む
. "$PSScriptRoot\env.ps1"
JSONから読み込む

# JSONから設定を読み込む
# ファイル内容 { "hostname": "pc-hogehoge" }
# JSONのキー名に-(ハイフン)は使用しない(コマンドレットとして誤認識するから)
$config = ConvertFrom-Json -InputObject (Get-Content $ConfigFilePath -Raw)
$hostName = $config.hostname
テキストファイル読み書き

$str = "hogehoge"
# 書き込み
Set-Content test.txt $str
# 追記
Add-Content test.txt "追記"
# 読み込み
$read_str = Get-Content test.txt 
# 文字コード指定で出力
Set-Content test.txt $str -encoding UTF8 # UTF-8で書き込み
基本文法

# コメント
# if
if ($a -eq 5) {
} elseif($a -gt 5) {
} else {
}
# for
for ($i = 0 ; $i -le 10 ; $i++) {
}
# foreach
$a = @("A", "B", "C") 
foreach ($item in $a) {
}
Hyper-Vコマンド

# HYPER-V のコマンドの一覧を返す
Get-Command -Module hyper-v | Out-GridView
# 仮想マシンの一覧を返す
Get-VM
# 動作中の仮想マシンの一覧
Get-VM | where {$_.State -eq 'Running'}
# 停止の仮想マシンの一覧
Get-VM | where {$_.State -eq 'Off'}
# 起動
Start-VM -Name (仮想マシン名)
# 動作中の仮想マシンを停止する
Get-VM | where {$_.State -eq 'Running'} | Stop-VM
# チェックポイントを作成する
Get-VM -Name (仮想マシン名) | Checkpoint-VM -SnapshotName (チェックポイント名)
指定フォルダからファイルリスト取得

# "C:¥hogehoge"フォルダからファイルの一覧を取得する
$folderFileList = Get-ChildItem -Path "C:¥hogehoge" -File
# 取得したファイルの数だけループする
foreach($item in $folderFileList) {
    # ファイル名を表示する
    Write-Host $item.Name # .FullName ならフルパス
}

# "C:¥hogehoge¥"フォルダの"*.txt"の一覧を取得する(Includeを指定する場合でRecurseを指定しない場合はPath指定に*が必要らしい)
$folderFileList = Get-ChildItem -Path "C:¥hogehoge¥*" -Include "*.txt"

# "C:¥hogehoge¥"フォルダとサブフォルダの"*.txt"の一覧を取得する
$folderFileList = Get-ChildItem -Path "C:¥hogehoge¥" -Recurse -Include "*.txt"

環境変数とデスクトップフォルダ

# 環境変数の一覧
Get-ChildItem -Path env:

# デスクトップフォルダを取得1 環境変数から組み立て
$desctopPath = $Env:HOMEDRIVE + $Env:HOMEPATH + "¥Desktop"

# デスクトップフォルダを取得2 System.Environmentから取得
$desctopPath = [System.Environment]::GetFolderPath("Desktop")

# スクリプト自身のパス
$MyInvocation.MyCommand.Path
いろいろ

# 年月日(yyyyMMddHHmmss形式)を取得
$yyyyMMddhhmmss = Get-Date -Format "yyyyMMddHHmmss"

# 式の途中で呼び出す
$filename = "ファイル_" + (Get-Date -Format "yyyyMMdd") + ".txt"
連想配列

# 作成
$hash = @{ "A"="AA"; "B"="BB" }

# 要素の取得
$hash["A"]
$hash.A

# ハッシュのループ
# for($entry in $hash.Keys){}
for($entry in $hash.GetEnumerator()){
  $entry.Key
  $entry.Value
}
Environmentクラス

# System.Environmentクラスの利用
# メンバーの一覧を表示(staticメンバー)
[System.Environment] | Get-Member -Static
# OSバージョンを表示する
[System.Environment]::OSVersion
Mathクラス

# System.Mathクラスの利用
# メンバーの一覧を表示(staticメソッド)
[System.Math] | Get-Member -Static -MemberType Methods
# ルート3を計算する
[System.Math]::Sqrt(9)
WebClient

$webClient = New-Object System.Net.WebClient
$webClient.DownloadString("http://URL/") > url.html
メール送信

# メール送信 非推奨なので注意
Send-MailMessage
終了

# スクリプト終了
exit
starz的テンプレート

#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# starz的テンプレート
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# デスクトップ
#$desctopPath = [System.Environment]::GetFolderPath("Desktop")

#-------------------
# 処理ルーチン
#-------------------
Function Execute(){
  Param(
    [string]$pExcelFile
  )
  $excel = New-Object -ComObject Excel.Application
  $book = $excel.Workbooks.Open("C:\hogehoge.xlsx")

  # シートループ
  foreach ($sheet in $excel.Worksheets) {
    $sheetname = $sheet.Name
    Write-Host $sheetname
  }
  # Bookをとじる
  [void]$book.Close($false)
  [System.Runtime.Interopservices.Marshal]::ReleaseComObject($book)
  # Excelの終了
  [void]$excel.Quit()
  [System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)

} #Execute

#-------------------
# 起動ルーチン
#-------------------
Function Main {
  Param(
    [parameter(mandatory=$true)]$param1
  )

  if ((Test-Path $param1) -eq $False){
    Write-Host "ファイルがありません"
    exit
  }

  # 処理起動
  Execute $param1

} #Main

# 起動
Main $Args

WinSCPを使ってLinuxサーバのファイルを取得する

param (
    # 引数1: 接続先URI(ユーザー名・パスワードを含む)
    # 例: sftp://user:password@192.168.1.100/
    [string]$Uri,

    # 引数2: Linux上の取得対象ファイル(フルパス)
    # 例: /home/test/test.csv
    [string]$RemoteFile,

    # 引数3: Windows側の保存先(フルパス)
    # 例: C:\work\download\test.csv
    [string]$LocalFile
)

# WinSCPのコマンドライン版
$WinScp = "C:\Program Files (x86)\WinSCP\WinSCP.com"

# WinSCPでファイルを取得
& $WinScp /command `
    "open $Uri" `
    "get `"$RemoteFile`" `"$LocalFile`"" `
    "exit"

# WinSCPの終了コードをBATへ返す
exit $LASTEXITCODE
DBからデータを取得してExcelに貼る(ClosedXMLを使用)

param(
    [Parameter(Mandatory = $true)]
    [string]$Rdbms,

    [Parameter(Mandatory = $true)]
    [string]$SqlFile,

    [Parameter(Mandatory = $true)]
    [string]$OutputFile
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

# ============================================================
# 設定 & 設定ファイルの存在チェック
# ============================================================
$BaseDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$configFile = Join-Path $BaseDir "config\$Rdbms.conf"
$closedXmlDll = Join-Path $BaseDir "lib\ClosedXML.dll"

if (-not (Test-Path $configFile)) {
    throw "接続設定ファイルが存在しません: $configFile"
}
if (-not (Test-Path $SqlFile)) {
    throw "SQLファイルが存在しません: $SqlFile"
}
if (-not (Test-Path $closedXmlDll)) {
    throw "ClosedXML.dllが存在しません: $closedXmlDll"
}

# ============================================================
# ClosedXML読み込み
# ============================================================
Add-Type -Path $closedXmlDll

# ============================================================
# 設定ファイル読み込み
#
# 形式:
# Server=localhost
# Database=TESTDB
# UserId=testuser
# Password=testpassword
# ============================================================
$config = @{}
foreach ($line in Get-Content $configFile -Encoding UTF8) {
    $line = $line.Trim()

    # 空行・コメント行は無視
    if ([string]::IsNullOrWhiteSpace($line)) {
        continue
    }

    if ($line.StartsWith("#")) {
        continue
    }

    $parts = $line.Split("=", 2)

    if ($parts.Count -ne 2) {
        continue
    }

    $key = $parts[0].Trim()
    $value = $parts[1].Trim()

    $config[$key] = $value
}

# ============================================================
# 接続文字列作成
# ============================================================
$requiredKeys = @(
    "Server",
    "Database"
)

foreach ($key in $requiredKeys) {
    if (-not $config.ContainsKey($key)) {
        throw "設定ファイルに '$key' がありません: $configFile"
    }
}

$connectionStringBuilder =
    New-Object System.Data.SqlClient.SqlConnectionStringBuilder

$connectionStringBuilder["Data Source"] = $config["Server"]
$connectionStringBuilder["Initial Catalog"] = $config["Database"]

if ($config.ContainsKey("UserId") -and
    $config.ContainsKey("Password")) {

    $connectionStringBuilder["User ID"] = $config["UserId"]
    $connectionStringBuilder["Password"] = $config["Password"]
}
else {
    # UserId / PasswordがなければWindows認証
    $connectionStringBuilder["Integrated Security"] = $true
}

$connectionString = $connectionStringBuilder.ConnectionString

# ============================================================
# SQLファイル読み込み
# ============================================================
$sqlText = Get-Content $SqlFile -Raw -Encoding UTF8

# ============================================================
# SQLを分割
#
# -- [シート名]
# SELECT ...
#
# -- [シート名]
# SELECT ...
# ============================================================

$pattern = '(?ms)^\s*--\s*\[(.+?)\]\s*\r?\n(.*?)(?=^\s*--\s*\[.+?\]\s*$|\z)'

$matches = [regex]::Matches($sqlText, $pattern)

if ($matches.Count -eq 0) {
    throw "SQLファイルに '-- [シート名]' 形式のSQLがありません。"
}

# ============================================================
# Excel作成
# ============================================================

$workbook = New-Object ClosedXML.Excel.XLWorkbook

try {

    foreach ($match in $matches) {

        $sheetName = $match.Groups[1].Value.Trim()
        $sql = $match.Groups[2].Value.Trim()

        if ([string]::IsNullOrWhiteSpace($sheetName)) {
            continue
        }

        if ([string]::IsNullOrWhiteSpace($sql)) {
            continue
        }

        Write-Host "SQL実行: [$sheetName]"

        # ------------------------------------------------------
        # シート名の長さ・使用禁止文字チェック
        # ------------------------------------------------------

        if ($sheetName.Length -gt 31) {
            throw "シート名が31文字を超えています: $sheetName"
        }

        if ($sheetName -match '[\\\/\?\*\[\]\:]') {
            throw "シート名に使用できない文字があります: $sheetName"
        }

        # ------------------------------------------------------
        # SQL実行
        # ------------------------------------------------------

        $connection = New-Object System.Data.SqlClient.SqlConnection
        $connection.ConnectionString = $connectionString

        try {

            $connection.Open()

            $command = $connection.CreateCommand()
            $command.CommandText = $sql
            $command.CommandTimeout = 0

            $adapter =
                New-Object System.Data.SqlClient.SqlDataAdapter($command)

            $table = New-Object System.Data.DataTable

            [void]$adapter.Fill($table)

        }
        finally {

            if ($connection.State -ne
                [System.Data.ConnectionState]::Closed) {

                $connection.Close()
            }

            $connection.Dispose()
        }

        Write-Host "  件数: $($table.Rows.Count)"

        # ------------------------------------------------------
        # シート作成
        # ------------------------------------------------------

        $sheet = $workbook.Worksheets.Add($sheetName)

        $columnCount = $table.Columns.Count

        # ------------------------------------------------------
        # ヘッダ
        # ------------------------------------------------------

        for ($col = 0; $col -lt $columnCount; $col++) {

            $cell = $sheet.Cell(1, $col + 1)

            $cell.SetValue(
                [string]$table.Columns[$col].ColumnName
            )

            $cell.Style.Font.Bold = $true

            $cell.Style.Fill.BackgroundColor =
                [ClosedXML.Excel.XLColor]::LightBlue

            $cell.Style.Alignment.Horizontal =
                [ClosedXML.Excel.XLAlignmentHorizontalValues]::Center
        }

        # ------------------------------------------------------
        # データ
        # DBの型をExcelへ持ち込まず、すべて文字列として設定する
        # ------------------------------------------------------

        for ($row = 0; $row -lt $table.Rows.Count; $row++) {

            for ($col = 0; $col -lt $columnCount; $col++) {

                $value = $table.Rows[$row][$col]

                if ($value -eq [DBNull]::Value) {
                    $text = ""
                } else {
                    $text = [string]$value
                }

                $cell = $sheet.Cell(
                    $row + 2,
                    $col + 1
                )

                # 文字列として設定
                $cell.SetValue($text)

                # Excel側も文字列として扱わせる
                $cell.Style.NumberFormat.Format = "@"
            }
        }

        # ------------------------------------------------------
        # 罫線
        # ------------------------------------------------------
        $lastRow = [Math]::Max(
            1,
            $table.Rows.Count + 1
        )

        if ($columnCount -gt 0) {
            $range = $sheet.Range(
                1,
                1,
                $lastRow,
                $columnCount
            )
            $range.Style.Border.OutsideBorder =
                [ClosedXML.Excel.XLBorderStyleValues]::Thin
            $range.Style.Border.InsideBorder =
                [ClosedXML.Excel.XLBorderStyleValues]::Thin
        }

        # ------------------------------------------------------
        # 列幅自動調整
        # ------------------------------------------------------
        if ($columnCount -gt 0) {

            $sheet.Columns().AdjustToContents()

            # 極端に幅が広くなることを防止
            foreach ($column in $sheet.Columns()) {

                if ($column.Width -gt 50) {
                    $column.Width = 50
                }
            }
        }

        # ------------------------------------------------------
        # 1行目固定
        # ------------------------------------------------------
        $sheet.SheetView.FreezeRows(1)
    }

    # ========================================================
    # Excel保存
    # ========================================================
    $outputFullPath = [System.IO.Path]::GetFullPath($OutputFile)

    Write-Host ""
    Write-Host "Excel出力: $outputFullPath"

    $workbook.SaveAs($outputFullPath)

}
finally {

    $workbook.Dispose()
}

Write-Host ""
Write-Host "完了しました。"