«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Tags more
Archives
Today
Total
12-28 16:41
관리 메뉴

+1-1+1-1+1-1+1-1...

Exchange 2013 - 사서함 용량 DB에 저장 (쓰레드 사용) 본문

NT/Mail & Exchange

Exchange 2013 - 사서함 용량 DB에 저장 (쓰레드 사용)

투명인간 2021. 3. 5. 23:51
728x90

대량의 사서함을 호스팅하는 Exchange 환경에서 메일 사서함의 용량을 전부 찾아 처리하는 방식을 시간이 오래 걸린다.

이를 보완하기위 Powershell에 지원하는 쓰레드를 사용하여 시사험 용량을 DB에 저장하는 코드를 작성해보았다.

 

 
function Invoke-Async{
param(
#The data group to process, such as server names.
[parameter(Mandatory=$true,ValueFromPipeLine=$true)]
[object[]]$Set,
#The parameter name that the set belongs to, such as Computername.
[parameter(Mandatory=$true)]
[string] $SetParam,
#The Cmdlet for Function you'd like to process with.
[parameter(Mandatory=$true, ParameterSetName='cmdlet')]
[string]$Cmdlet,
#The ScriptBlock you'd like to process with
[parameter(Mandatory=$true, ParameterSetName='ScriptBlock')]
[scriptblock]$ScriptBlock,
#any aditional parameters to be forwarded to the cmdlet/function/scriptblock
[hashtable]$Params,
#number of jobs to spin up, default being 10.
[int]$ThreadCount=10,
#return performance data
[switch]$Measure
)
Begin
{

    $Threads = @()
    $Length = $JobsLeft = $Set.Length

    $Count = 0
    if($Length -lt $ThreadCount){$ThreadCount=$Length}
    $timer = @(1..$ThreadCount  | ForEach-Object{$null})
    $Jobs = @(1..$ThreadCount  | ForEach-Object{$null})
    
    If($PSCmdlet.ParameterSetName -eq 'cmdlet')
    {
        $CmdType = (Get-Command $Cmdlet).CommandType
        if($CmdType -eq 'Alias')
        {
            $CmdType = (Get-Command (Get-Command $Cmdlet).ResolvedCommandName).CommandType
        }
        
        If($CmdType -eq 'Function')
        {
            $ScriptBlock = (Get-Item Function:\$Cmdlet).ScriptBlock
            1..$ThreadCount | ForEach-Object{ $Threads += [powershell]::Create().AddScript($ScriptBlock)}
        }
        ElseIf($CmdType -eq "Cmdlet")
        {
            1..$ThreadCount  | ForEach-Object{ $Threads += [powershell]::Create().AddCommand($Cmdlet)}
        }
    }
    Else
    {
        1..$ThreadCount | ForEach-Object{ $Threads += [powershell]::Create().AddScript($ScriptBlock)}
    }

    If($Params){$Threads | ForEach-Object{$_.AddParameters($Params) | Out-Null}}

}
Process
{
    while($JobsLeft)
    {
        for($idx = 0; $idx -lt ($ThreadCount-1) ; $idx++)
        {
            $SetParamObj = $Threads[$idx].Commands.Commands[0].Parameters| Where-Object {$_.Name -eq $SetParam}
             
            If($Jobs[$idx].IsCompleted) #job ran ok, clear it out
            {  
                $result = $null
                if($threads[$idx].InvocationStateInfo.State -eq "Failed")
                {
                    $result  = $Threads[$idx].InvocationStateInfo.Reason
                    Write-Error "Set Item: $($SetParamObj.Value) Exception: $result"
                }
                else
                { 
                    $result = $Threads[$idx].EndInvoke($Jobs[$idx])
                }
                $ts = (New-TimeSpan -Start $timer[$idx] -End (Get-Date))
                if($Measure)
                {
                    new-object psobject -Property @{
                        TimeSpan = $ts
                        Output = $result
                        SetItem = $SetParamObj.Value}
                }
                else
                {
                    $result
                }
                $Jobs[$idx] = $null
                $JobsLeft-- #one less left
                write-verbose "Completed: $($SetParamObj.Value) in $ts"
                write-progress -Activity "Processing Set" -Status "$JobsLeft jobs left" -PercentComplete (($length-$jobsleft)/$length*100)
            }
            If(($Count -lt $Length) -and ($Jobs[$idx] -eq $null)) #add job if there is more to process
            {
                write-verbose "starting: $($Set[$Count])"
                $timer[$idx] = get-date
                $Threads[$idx].Commands.Commands[0].Parameters.Remove($SetParamObj) | Out-Null #check for success?
                $Threads[$idx].AddParameter($SetParam,$Set[$Count]) | Out-Null
                $Jobs[$idx] = $Threads[$idx].BeginInvoke()
                $Count++
            }
        }

    }
}
End
{
    $Threads | ForEach-Object{$_.runspace.close();$_.Dispose()}
}
}


cls

$sb = [scriptblock] {
        Param (
        [string]$object
        )
        
        $limit = 0
        Add-PSSnapin -Name "Microsoft.Exchange.Management.PowerShell.SnapIn"
        
        # DB 연결 정보는 환경에 따라 달라짐
        $ConnectionString = "Server=vs-db\instance;Database=MailData;Integrated Security=True;Connect Timeout=30"
        $conn = New-Object System.Data.sqlClient.SQLConnection
        $conn.connectionstring = $ConnectionString
        $conn.Open()
        $sqlCmd = New-Object System.Data.sqlClient.SqlCommand

        $Result = @()
        $StartTime = (get-date -Format "yyyy-MM-dd HH:mm:ss")

        if($limit -eq 0){
            Get-Mailbox -Database $object -ResultSize unlimited | ?{$_.DisplayName -notlike '*퇴직자*'} | %{
                #$DB = New-Object psobject
                $dateTime = (get-date -Format "yyyy-MM-dd HH:mm:ss")
                #$DB | Add-Member Noteproperty -Name "Date" -Value $dateTime
                #$DB | Add-Member Noteproperty -Name "SamAccountName" -Value $_.SamAccountName
                #$DB | Add-Member Noteproperty -Name "Name" -Value $_.Name
                #$DB | Add-Member Noteproperty -Name "PrimarySmtpAddress" -Value $_.PrimarySmtpAddress
                
                if($_.UseDatabaseQuotaDefaults -ne $true){
                    $IssueWarningQuota = ($_.IssueWarningQuota.Value.ToMB())
                }else{
                    $IssueWarningQuota = ((Get-MailboxDatabase -Identity $object).IssueWarningQuota.Value.ToMB())
                }

                #$DB | Add-Member Noteproperty -Name "IssueWarningQuota" -Value $IssueWarningQuota
                
                #$Result += $DB
                Get-MailboxStatistics -Identity $_.Identity | %{
                    $TotalItemSize = ($_.TotalItemSize.Value.ToMB())
                    $ItemCount = $_.ItemCount
                    #$DB | Add-Member Noteproperty -Name "ItemCount" -Value $ItemCount
                    #$DB | Add-Member Noteproperty -Name "TotalItemSize" -Value $TotalItemSize
                }

                $query = "INSERT INTO MailData.dbo.TB_MAILUSERQUOTA (date,SamAccountName,Name,PrimarySmtpAddress,IssueWarningQuota,TotalItemSize,ItemCount,MailDB) VALUES ('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}')" -f $dateTime, $_.SamAccountName, $_.Name, $_.PrimarySmtpAddress, $IssueWarningQuota, $TotalItemSize,$ItemCount,$object
                $sqlCmd.CommandText = $query
                $sqlCmd.Connection = $conn
                $sqlCmd.CommandTimeout = 30
                $sqlCmd.ExecuteNonQuery()

            }

        }else{
            Get-Mailbox -Database $object -ResultSize $limit | %{
                #$DB = New-Object psobject
                $dateTime = (get-date -Format "yyyy-MM-dd HH:mm:ss")
                #$DB | Add-Member Noteproperty -Name "Date" -Value $dateTime
                #$DB | Add-Member Noteproperty -Name "SamAccountName" -Value $_.SamAccountName
                #$DB | Add-Member Noteproperty -Name "Name" -Value $_.Name
                #$DB | Add-Member Noteproperty -Name "PrimarySmtpAddress" -Value $_.PrimarySmtpAddress
                
                if($_.UseDatabaseQuotaDefaults -ne $true){
                    $IssueWarningQuota = ($_.IssueWarningQuota.Value.ToMB())
                }else{
                    $IssueWarningQuota = ((Get-MailboxDatabase -Identity $object).IssueWarningQuota.Value.ToMB())
                }

                #$DB | Add-Member Noteproperty -Name "IssueWarningQuota" -Value $IssueWarningQuota
                
                #$Result += $DB
                Get-MailboxStatistics -Identity $_.Identity | %{
                    $TotalItemSize = ($_.TotalItemSize.Value.ToMB())
                    $ItemCount = $_.ItemCount
                    #$DB | Add-Member Noteproperty -Name "ItemCount" -Value $ItemCount
                    #$DB | Add-Member Noteproperty -Name "TotalItemSize" -Value $TotalItemSize
                }

                $query = "INSERT INTO MailData.dbo.TB_MAILUSERQUOTA (date,SamAccountName,Name,PrimarySmtpAddress,IssueWarningQuota,TotalItemSize,ItemCount,MailDB) VALUES ('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}')" -f $dateTime, $_.SamAccountName, $_.Name, $_.PrimarySmtpAddress, $IssueWarningQuota, $TotalItemSize,$ItemCount,$object
                $sqlCmd.CommandText = $query
                $sqlCmd.Connection = $conn
                $sqlCmd.CommandTimeout = 30
                $result = $sqlCmd.ExecuteNonQuery()
            }

        }

        $delquery = "delete from [dbo].[TB_MAILUSERQUOTA] where Date < '{0}' and MailDB = '{1}'" -f $StartTime,$object
        $sqlCmd.CommandText = $delquery
        $sqlCmd.Connection = $conn
        $sqlCmd.CommandTimeout = 30
        $result = $sqlCmd.ExecuteNonQuery()
        
        
        $conn.Close()

        return $Result
        
   }


$object = (Get-MailboxDatabaseCopyStatus -Server $env:computername  | ? {$_.Status -eq "Mounted" -and $_.Name -notlike "OABMBX*"}).databasename

if($object.count -ne 0){
    $rtn = Invoke-Async -Set $object -SetParam object -ScriptBlock $sb -ThreadCount $object.count -Verbose 
}

PowerShell Gallery | Invoke-Async.ps1 1.0.3

 

PowerShell Gallery | Invoke-Async.ps1 1.0.3

 

www.powershellgallery.com

PowerShell: Run SQL Update command (ExecuteNonQuery) (mylifeismymessage.net)

 

PowerShell: Run SQL Update command (ExecuteNonQuery)

How to run a SQL command against a Microsoft SQL Server Database (MSSQL) from a PowerShell script. cls $datasource = "server=server\instance;database=mydb;trusted_connection=true" #if not using Integrated Security, #you might want to pass user/pass in vari

mylifeismymessage.net

 

반응형