SQL Server 2008 Job Agent 執行記錄匯出工具


(1)建立專用的低權限SQL帳號 - 可以建立一個只有讀取Job Agent記錄權限的專用SQL帳號,而非使用高權限的sa帳號。

建立SQL登入帳號 :

USE [master]
GO
CREATE LOGIN [JobLogReader] WITH PASSWORD=N'複雜密碼', DEFAULT_DATABASE=[msdb], CHECK_EXPIRATION=ON, CHECK_POLICY=ON
GO


在msdb資料庫中建立使用者
USE [msdb]
GO
CREATE USER [JobLogReader] FOR LOGIN [JobLogReader]
GO

授予最小權限
USE [msdb]
GO
-- 授予讀取sysjobs和sysjobhistory表的權限
GRANT SELECT ON sysjobs TO [JobLogReader]
GRANT SELECT ON sysjobhistory TO [JobLogReader]
GRANT SELECT ON sysjobsteps TO [JobLogReader]
GO




(2)

<#
.SYNOPSIS
    撈取SQL Server 2008 Job Agent執行狀況的LOG並匯出為.log檔案

.DESCRIPTION
    此腳本用於從SQL Server 2008撈取Job Agent的執行記錄,並使用BCP命令將結果匯出為.log檔案
    匯出的檔案格式與SQL Server Agent圖形介面匯出的格式相容,可再次匯入
    腳本使用安全的方式處理SQL Server連線憑證,避免明碼存儲

.PARAMETER ServerInstance
    SQL Server的實例名稱,例如:"SERVERNAME\INSTANCENAME"

.PARAMETER Database
    包含Job Agent記錄的資料庫名稱,通常為"msdb"

.PARAMETER Days
    要撈取的天數範圍,例如:7表示撈取最近7天的記錄

.PARAMETER OutputPath
    匯出的.log檔案路徑

.EXAMPLE
    .\Export-JobAgentLog.ps1 -ServerInstance "SQLSERVER01\SQL2008" -Database "msdb" -Days 7 -OutputPath "C:\Logs\JobAgentLog.log"

.NOTES
    作者: AI助手
    日期: 2023-11-01
    版本: 1.0
    需求: Windows Server 2008, SQL Server 2008, PowerShell 2.0+
#>

[CmdletBinding()]
param (
    [Parameter(Mandatory = $true)]
    [string]$ServerInstance,
    
    [Parameter(Mandatory = $true)]
    [string]$Database = "msdb",
    
    [Parameter(Mandatory = $true)]
    [int]$Days = 7,
    
    [Parameter(Mandatory = $true)]
    [string]$OutputPath
)

function Get-SecureCredentials {
    <#
    .SYNOPSIS
        安全地獲取SQL Server連線憑證
    .DESCRIPTION
        此函數嘗試從加密的憑證檔案讀取憑證,如果檔案不存在則提示使用者輸入並儲存
    #>
    param (
        [Parameter(Mandatory = $false)]
        [switch]$UseStoredCredential = $true,
        
        [Parameter(Mandatory = $false)]
        [string]$CredentialPath = "$env:USERPROFILE\Documents\SQLServerCredential.xml"
    )
    
    $credential = $null
    
    try {
        # 檢查是否使用儲存的憑證
        if ($UseStoredCredential -and (Test-Path -Path $CredentialPath)) {
            Write-Verbose "正在從檔案讀取儲存的憑證..."
            $credential = Import-Clixml -Path $CredentialPath
            Write-Verbose "已成功讀取儲存的憑證。"
        }
        else {
            # 提示使用者輸入SQL Server的使用者名稱和密碼
            $credential = Get-Credential -Message "請輸入SQL Server的登入憑證" -UserName "JobLogReader"
            
            if ($null -eq $credential) {
                Write-Error "未提供有效的憑證,程序終止。"
                exit 1
            }
            
            # 詢問是否儲存憑證
            $saveCredential = Read-Host "是否要儲存此憑證以便自動執行?(Y/N)"
            
            if ($saveCredential -eq "Y" -or $saveCredential -eq "y") {
                # 確保目錄存在
                $credentialDir = Split-Path -Path $CredentialPath -Parent
                if (-not (Test-Path -Path $credentialDir)) {
                    New-Item -Path $credentialDir -ItemType Directory -Force | Out-Null
                }
                
                # 將憑證加密儲存到檔案
                $credential | Export-Clixml -Path $CredentialPath -Force
                Write-Host "憑證已安全地儲存到 $CredentialPath" -ForegroundColor Green
                Write-Host "下次執行時將自動使用此憑證。" -ForegroundColor Green
            }
        }
    }
    catch {
        Write-Error "獲取憑證時發生錯誤: $_"
        exit 1
    }
    
    return $credential
}

function Test-SQLConnection {
    <#
    .SYNOPSIS
        測試SQL Server連線
    .DESCRIPTION
        此函數測試與SQL Server的連線是否成功
    #>
    param (
        [string]$ServerInstance,
        [string]$Database,
        [System.Management.Automation.PSCredential]$Credential
    )
    
    try {
        $username = $Credential.UserName
        $password = $Credential.GetNetworkCredential().Password
        
        # 建立連線字串
        $connectionString = "Server=$ServerInstance;Database=$Database;User Id=$username;Password=$password;"
        
        # 建立SQL連線
        $connection = New-Object System.Data.SqlClient.SqlConnection($connectionString)
        $connection.Open()
        
        # 如果能夠開啟連線,則關閉連線並返回成功
        $connection.Close()
        return $true
    }
    catch {
        Write-Error "SQL連線測試失敗: $_"
        return $false
    }
}

function Get-JobAgentLogQuery {
    <#
    .SYNOPSIS
        生成用於撈取Job Agent LOG的SQL查詢
    .DESCRIPTION
        此函數根據指定的天數範圍生成SQL查詢,用於撈取Job Agent的執行記錄
    #>
    param (
        [int]$Days
    )
    
    # 生成SQL查詢,撈取指定天數範圍內的Job Agent執行記錄
    # 此查詢格式確保匯出的記錄可以再次匯入到SQL Server Agent
    $query = @"
SELECT
    j.name AS [作業名稱],
    h.step_id AS [步驟識別碼],
    h.step_name AS [步驟名稱],
    CASE h.run_status
        WHEN 0 THEN N'失敗'
        WHEN 1 THEN N'成功'
        WHEN 2 THEN N'重試'
        WHEN 3 THEN N'取消'
        WHEN 4 THEN N'進行中'
        ELSE N'未知'
    END AS [執行狀態],
    h.message AS [訊息],
    h.run_date AS [執行日期],
    h.run_time AS [執行時間],
    h.run_duration AS [執行持續時間],
    h.operator_id_emailed AS [已寄電子郵件給操作員識別碼],
    h.operator_id_netsent AS [已傳送網路訊息給操作員識別碼],
    h.operator_id_paged AS [已呼叫操作員識別碼],
    h.retries_attempted AS [嘗試重試次數],
    h.server AS [伺服器]
FROM msdb.dbo.sysjobhistory h
JOIN msdb.dbo.sysjobs j ON h.job_id = j.job_id
WHERE CONVERT(datetime, STUFF(STUFF(CAST(h.run_date AS varchar), 7, 0, '-'), 5, 0, '-')) >= DATEADD(day, -$Days, GETDATE())
ORDER BY h.run_date DESC, h.run_time DESC
"@
    
    return $query
}

function Export-JobAgentLog {
    <#
    .SYNOPSIS
        使用BCP命令匯出Job Agent LOG
    .DESCRIPTION
        此函數使用BCP命令將SQL查詢結果匯出為.log檔案
    #>
    param (
        [string]$ServerInstance,
        [string]$Database,
        [System.Management.Automation.PSCredential]$Credential,
        [string]$Query,
        [string]$OutputPath
    )
    
    try {
        $username = $Credential.UserName
        $password = $Credential.GetNetworkCredential().Password
        
        # 將查詢儲存到臨時檔案
        $tempQueryFile = [System.IO.Path]::GetTempFileName()
        $Query | Out-File -FilePath $tempQueryFile -Encoding UTF8
        
        Write-Host "正在匯出Job Agent執行記錄到 $OutputPath..." -ForegroundColor Cyan
        
        # 使用BCP命令匯出查詢結果
        # 注意:這裡使用-c參數表示字元格式,確保匯出的格式與SQL Server Agent圖形介面匯出的格式相容
        $bcpCommand = "bcp \"$Query\" queryout \"$OutputPath\" -c -t\"\t\" -r\"\n\" -S\"$ServerInstance\" -U\"$username\" -P\"$password\" -d\"$Database\""
        
        # 使用Invoke-Expression執行BCP命令
        # 注意:這裡不直接顯示BCP命令,以避免在日誌中顯示密碼
        Write-Verbose "執行BCP命令匯出資料..."
        Invoke-Expression $bcpCommand | Out-Null
        
        # 刪除臨時查詢檔案
        if (Test-Path $tempQueryFile) {
            Remove-Item -Path $tempQueryFile -Force
        }
        
        # 檢查匯出檔案是否存在
        if (Test-Path $OutputPath) {
            $fileInfo = Get-Item $OutputPath
            Write-Host "匯出完成!檔案大小: $([math]::Round($fileInfo.Length / 1KB, 2)) KB" -ForegroundColor Green
            Write-Host "檔案路徑: $OutputPath" -ForegroundColor Green
        }
        else {
            Write-Error "匯出失敗,無法找到輸出檔案。"
            return $false
        }
        
        return $true
    }
    catch {
        Write-Error "匯出Job Agent LOG時發生錯誤: $_"
        return $false
    }
}

# 新增參數,用於控制是否使用儲存的憑證
[CmdletBinding()]
param (
    [Parameter(Mandatory = $true)]
    [string]$ServerInstance,
    
    [Parameter(Mandatory = $true)]
    [string]$Database = "msdb",
    
    [Parameter(Mandatory = $true)]
    [int]$Days = 7,
    
    [Parameter(Mandatory = $true)]
    [string]$OutputPath,
    
    [Parameter(Mandatory = $false)]
    [switch]$UseStoredCredential = $true,
    
    [Parameter(Mandatory = $false)]
    [string]$CredentialPath = "$env:USERPROFILE\Documents\SQLServerCredential.xml"
)

# 主程序
try {
    # 檢查輸出路徑的目錄是否存在,如果不存在則創建
    $outputDir = Split-Path -Path $OutputPath -Parent
    if (-not (Test-Path -Path $outputDir)) {
        New-Item -Path $outputDir -ItemType Directory -Force | Out-Null
        Write-Host "已創建輸出目錄: $outputDir" -ForegroundColor Yellow
    }
    
    # 獲取安全的SQL Server連線憑證
    if ($UseStoredCredential) {
        Write-Host "嘗試使用儲存的SQL Server憑證..." -ForegroundColor Cyan
    } else {
        Write-Host "請提供SQL Server的登入憑證..." -ForegroundColor Cyan
    }
    
    $credential = Get-SecureCredentials -UseStoredCredential $UseStoredCredential -CredentialPath $CredentialPath
    
    # 測試SQL Server連線
    Write-Host "正在測試SQL Server連線..." -ForegroundColor Cyan
    $connectionTest = Test-SQLConnection -ServerInstance $ServerInstance -Database $Database -Credential $credential
    
    if (-not $connectionTest) {
        Write-Error "無法連線到SQL Server,請檢查連線參數和憑證。"
        exit 1
    }
    
    Write-Host "SQL Server連線成功!" -ForegroundColor Green
    
    # 生成SQL查詢
    Write-Host "正在生成SQL查詢,撈取最近 $Days 天的Job Agent執行記錄..." -ForegroundColor Cyan
    $query = Get-JobAgentLogQuery -Days $Days
    
    # 匯出Job Agent LOG
    $exportResult = Export-JobAgentLog -ServerInstance $ServerInstance -Database $Database -Credential $credential -Query $query -OutputPath $OutputPath
    
    if ($exportResult) {
        Write-Host "操作完成!Job Agent執行記錄已成功匯出。" -ForegroundColor Green
        Write-Host "此檔案可以透過SQL Server Agent圖形介面匯入。" -ForegroundColor Green
    }
    else {
        Write-Error "匯出Job Agent執行記錄失敗。"
        exit 1
    }
}
catch {
    Write-Error "執行腳本時發生錯誤: $_"
    exit 1
}


目前PowerShell腳本中使用DPAPI的部分是在儲存憑證時,透過`ConvertFrom-SecureString` 和`ConvertTo-SecureString` 命令,這些命令內部使用Windows的DPAPI來加密和解密密碼。


如果使用了`-UseStoredCredential $true` 參數並事先儲存了憑證,腳本就不需要每次都輸入憑證。這種方式適合排程自動化,因為它可以在無人值守的情況下執行。

但請注意,儲存的憑證只能被建立它的Windows使用者帳戶解密,所以排程任務必須使用相同的使用者帳戶執行。



SQL Server 2008 Job Agent 執行記錄匯出工具

功能簡介

此工具用於從 SQL Server 2008 撈取 Job Agent 的執行記錄,並使用 BCP 命令將結果匯出為 .log 檔案。匯出的檔案格式與 SQL Server Agent 圖形介面匯出的格式相容,可再次匯入。

主要特點

  • 可設定日期範圍(N 天內)撈取 Job Agent 執行記錄
  • 使用 BCP 命令匯出資料為 .log 檔案
  • 安全處理 SQL Server 連線憑證,避免明碼存儲
  • 匯出的檔案可從 SQL Server Agent 圖形介面匯入
  • 適用於 Windows Server 2008 環境

系統需求

  • Windows Server 2008 或更高版本
  • SQL Server 2008 或更高版本
  • PowerShell 2.0 或更高版本
  • BCP 工具(SQL Server 客戶端工具的一部分)

使用方法

基本用法


.\Export-JobAgentLog.ps1 -ServerInstance "SQLSERVER01\SQL2008" -Database "msdb" -Days 7 -OutputPath "C:\Logs\JobAgentLog.log"

自動化執行(適用於 Windows 排程任務)


# 使用已儲存的憑證自動執行
.\Export-JobAgentLog.ps1 -ServerInstance "SQLSERVER01\SQL2008" -Database "msdb" -Days 7 -OutputPath "C:\Logs\JobAgentLog.log" -UseStoredCredential $true

參數說明

  • ServerInstance:SQL Server 的實例名稱,例如:"SERVERNAME\INSTANCENAME"
  • Database:包含 Job Agent 記錄的資料庫名稱,通常為 "msdb"
  • Days:要撈取的天數範圍,例如:7 表示撈取最近 7 天的記錄
  • OutputPath:匯出的 .log 檔案路徑
  • UseStoredCredential:是否使用已儲存的憑證(預設為 $true)
  • CredentialPath:憑證檔案的路徑(預設為使用者 Documents 資料夾中的 SQLServerCredential.xml)

安全性考量

此腳本使用 PowerShell 的 Get-Credential 命令安全地處理 SQL Server 連線憑證,避免在腳本中明碼存儲密碼。執行時可以選擇手動輸入 SQL Server 的使用者名稱和密碼,或使用安全存儲的憑證自動執行。

憑證會使用 Windows 資料保護 API (DPAPI) 加密後儲存在使用者的 Documents 資料夾中,只有建立憑證的使用者帳戶才能解密,確保安全性。

注意事項

  • 執行腳本需要對 SQL Server 的 msdb 資料庫有讀取權限
  • 匯出目錄需要有寫入權限
  • 如果匯出檔案已存在,將被覆蓋

留言

這個網誌中的熱門文章

何謂淨重(Net Weight)、皮重(Tare Weight)與毛重(Gross Weight)

(2021年度)駕訓學科筆試準備題庫歸納分析_法規是非題

Architecture(架構) 和 Framework(框架) 有何不同?_軟體設計前的事前規劃的藍圖概念