使用作业和哈希表的Powershell SQL备份

时间:2014-06-20 10:15:46

标签: powershell

我一直在努力使用我的脚本来备份我的SQL数据库并将各种信息返回到html文件以进行报告。我试图在备份运行时捕获一些特定的细节,然后再从备份文件本身检索其余信息。当我在单个服务器上以各种形式运行脚本时,它会运行,当我尝试在服务器列表上运行它时,它不起作用。

Set-Location \\DB\Powershell\SQLBackups

. .\SQLBackupFunctions.ps1

$JobFunction=
{
function backup_server_dbs 
{ 
    #backup function takes server name as a paramenter
    param([String]$ServerName) 

    #Load SMO features for powershell
    Push-Location
    Import-Module "SQLPS" -DisableNameChecking
    Pop-Location

    $nl = [Environment]::NewLine

    #create connection to SQL server, ensure timeout set to 25 minutes (default is 10 minutes which is too short for backups)
    $SQLSvr = New-Object -TypeName  Microsoft.SQLServer.Management.Smo.Server($ServerName)
    $SQLSvr.ConnectionContext.StatementTimeout = 0 

    #create database object type to be called in backup script
    $Db = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Database 

    $BackupFolder = "\\DB\SQL\BACKUPS\$($ServerName)\"

    $output = @{}

    #for each database on the SQL server instance (excluding system databases)
    foreach ($Db in $SQLSvr.Databases | Where-Object {@("tempdb", "model", "msdb", "ReportServer", "ReportServerTempDB") -notcontains $_.Name })
    {

        $BackupSetDescription = "Full Backup of "+$Db.Name 

        $BackupFileSuffix = ".dat" 


        #set backup file name
        $BackupName = $BackupFolder+$Db.Name+$BackupFileSuffix 

        $errorcatch = 0

        $btmp = @{}

        #useful error checking
        #try to backup the sql database
        try
        { 

            Backup-SqlDatabase -ServerInstance $ServerName -Database $Db.Name -BackupFile $BackupName -BackupSetDescription $BackupSetDescription -Initialize

        }#end try
        #catch any errors, add them to the output variable and set the error variable to 1 
        Catch [System.Exception]
        { 
            $btmp["Info"] = ($error[0].ToString())
            $btmp["Status"] = "Failed"
            $btmp["DatabaseName"] = $db.name
            $btmp["Serveranem"] = $ServerName

            $output.Add("$($servername)$($db.name)", $btmp)

            $errorcatch = 1 

        }#end catch
        #check error variable, if it is not 1, backup is successful and add success message to output variable, if not return output variable containing error information 
        Finally
        {
            if ($errorcatch -ne 1)
            { 
                $btmp["Info"] = "No information"
                $btmp["Status"] = "Success"
                $btmp["DatabaseName"] = $db.name
                $btmp["Serveranem"] = $ServerName

                $output.Add("$($servername)$($db.name)", $btmp)

            }#end if statement 

            $errorcatch = 0

        }#end finally statement


    }#end for each 

    return $output 

}#end function backup_server_dbs
}#end job function

#set up parameters for running jobs
$ScriptStartTime = Get-Date 
$BackupFileSuffix = "" 
$servers = @("server1",
         "server2",
         "server3",
         "server4",
         "server5") 
$jobs = @() 

foreach($servername in $servers)
{
#set location of backup folder    
$BackupFolder = "\\DB\SQL\BACKUPS\$($servername)\"

#test the location of the backup folder, if it does not exist then create the location
if ((Test-Path $BackupFolder) -eq $False)
{ 
    New-Item $BackupFolder -type Directory -Force
}#end if statement
}


#for each server in servers array run job function script block, add outputs to $jobs array
foreach ($servername in $servers)
{ 
$jobs += Start-job -ScriptBlock {backup_server_dbs $args[0]} -InitializationScript $JobFunction -ArgumentList($servername)  -Name $servername
}#end for each statement

$jobs | Wait-Job 

$nl = [Environment]::NewLine

$backupfiles = @()
$backups = @()

$finalreport = $null

$fulloutput = @{}

$index = 0

#for each job in jobs array simultaneously display the information and add it to the joutput variable (Tee-object), then remove the job from the array
foreach ($servername in $servers)
{ 
Receive-Job -Name $servername | Tee-Object -Variable joutput

$fulloutput.Add("$($servername)", $joutput)

#retrieve information from output and backup files themselves for report
$backupsummary = $null

$htmltableheader = "<p>
        <h2 align=""left"">$($servername)</h2> 
                    <table>
        <tr>
        <th>Database</th>
        <th>Result</th>
                    <th>Time Completed</th>
                    <th>Information</th>
                    <th>Size</th> 
                    </tr>"

$backupsummary += $htmltableheader

$BackupFolder = "\\DB\SQL\BACKUPS\$($servername)\"

$BackupFiles += Get-SQLBackupFiles -FilePath $BackupFolder -SQLServer $($servername)

foreach($File in $BackupFiles)
{ 
    $Backups = Get-BackupContents -FilePath $file -SQLServer $($servername)

    $htmltablerow = "<tr>"

    $key = "$($servername)$($backups.databasename)"

    if($fulloutput.Item($servername).Item($key).Item("Status") -eq "Failed")
    {
    $htmltablerow = $htmltablerow + "<td class=""fail"">$($backups.DatabaseName)</td>"
    $htmltablerow = $htmltablerow + "<td class=""fail"">Failed</td>"
    $htmltablerow = $htmltablerow + "<td class=""fail"">$($backups.BackupFinishDate)</td>"
    $htmltablerow = $htmltablerow + "<td class=""fail"">$($fulloutput.Item($key).Item("Info")) </td>"
    $htmltablerow = $htmltablerow + "<td class=""fail"">$([math]::Round($backups.BackupSize / 1MB))</td>"
    }
    else
    {
    $htmltablerow = $htmltablerow + "<td class=""pass"">$($backups.DatabaseName)</td>"
    $htmltablerow = $htmltablerow + "<td class=""pass"">Success</td>"
    $htmltablerow = $htmltablerow + "<td class=""pass"">$($backups.BackupFinishDate)</td>"
    $htmltablerow = $htmltablerow + "<td class=""pass"">$($fulloutput.Item($key).Item("Info")) </td>"
    $htmltablerow = $htmltablerow + "<td class=""pass"">$([math]::Round($backups.BackupSize / 1MB))</td>"
    }

    $htmltablerow = $htmltablerow + "</tr>"

    $backupsummary += $htmltablerow  
} 

$backupsummary += "</table>
                </p>"

$finalreport += $backupsummary

Remove-Job -Name $servername
} 

抛出此错误

Method invocation failed because [System.Object[]] doesn't contain a method named 'Item'.
At \\DB\Powershell\SQLBackups\SQLBackupsFull.ps1:176 char:46
+         if($fulloutput.Item($servername).Item <<<< ($key).Item("Status") -eq "Failed")
+ CategoryInfo          : InvalidOperation: (Item:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound

如果我稍微修改脚本并将重新发送作业信息的部分更改为

#for each job in jobs array simultaneously display the information and add it to the joutput variable (Tee-object), then remove the job from the array
foreach ($servername in $servers)
{ 
Receive-Job -Name $servername | Tee-Object -Variable joutput

#retrieve information from output and backup files themselves for report
$backupsummary = $null

$htmltableheader = "<p>
                    <h2 align=""left"">$($servername)</h2> 
                    <table>
                    <tr>
                    <th>Database</th>
                    <th>Result</th>
                    <th>Time Completed</th>
                    <th>Information</th>
                    <th>Size</th> 
                    </tr>"

$backupsummary += $htmltableheader

$BackupFolder = "\\ad.mitsubishi-trust.co.uk\MUTBROOT\DB\SQL\BACKUPS\$($servername)\"

$BackupFiles += Get-SQLBackupFiles -FilePath $BackupFolder -SQLServer $($servername)

foreach($File in $BackupFiles)
{ 
    $Backups = Get-BackupContents -FilePath $file -SQLServer $($servername)

    $htmltablerow = "<tr>"

    $key = "$($servername)$($backups.databasename)"

    if($joutput.Item($key).Item("Status") -eq "Failed")
    {
    $htmltablerow = $htmltablerow + "<td class=""fail"">$($backups.DatabaseName)</td>"
    $htmltablerow = $htmltablerow + "<td class=""fail"">Failed</td>"
    $htmltablerow = $htmltablerow + "<td class=""fail"">$($backups.BackupFinishDate)</td>"
    $htmltablerow = $htmltablerow + "<td class=""fail"">$($joutput.Item($key).Item("Info")) </td>"
    $htmltablerow = $htmltablerow + "<td class=""fail"">$([math]::Round($backups.BackupSize / 1MB))</td>"
    }
    else
    {
    $htmltablerow = $htmltablerow + "<td class=""pass"">$($backups.DatabaseName)</td>"
    $htmltablerow = $htmltablerow + "<td class=""pass"">Success</td>"
    $htmltablerow = $htmltablerow + "<td class=""pass"">$($backups.BackupFinishDate)</td>"
    $htmltablerow = $htmltablerow + "<td class=""pass"">$($joutput.Item($key).Item("Info")) </td>"
    $htmltablerow = $htmltablerow + "<td class=""pass"">$([math]::Round($backups.BackupSize / 1MB))</td>"
    }

    $htmltablerow = $htmltablerow + "</tr>"

    $backupsummary += $htmltablerow  
} 

$backupsummary += "</table>
                </p>"

$finalreport += $backupsummary

Remove-Job -Name $servername
} 

然后我得到了以下错误,并且我为使其工作所做的所有尝试通常都会导致此错误:

You cannot call a method on a null-valued expression.
At \\DB\Powershell\SQLBackups\SQLBackupsFull.ps1:170 char:36
+         if($joutput.Item($key).Item <<<< ("Status") -eq "Failed")
+ CategoryInfo          : InvalidOperation: (Item:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull

我已经对这个问题喋喋不休了好几天了,当$ servers数组只包含一个名字而不包含多个名字时,我无法弄清楚它为什么会起作用。我也尝试修改包含Receive-Job cmdlet的foreach来调用$ jobs中的每个$ job,然后使用$ job.name(这甚至可能吗??)而不是$ servername,但这也不起作用并且抛出上述空值错误。

编辑 *****************

感谢评论中的帮助,解决方案是使用

的组合
$joutput = Receive-job....

代替Tee-Object并使用

if($joutput.$($key).Status -eq "Failed")

而不是调用.Item方法

0 个答案:

没有答案