如何在 PowerShell 中将计算值写入 SQL INSERT/UPDATE

Posted

技术标签:

【中文标题】如何在 PowerShell 中将计算值写入 SQL INSERT/UPDATE【英文标题】:How to write calculated values to SQL INSERT/UPDATE in PowerShell 【发布时间】:2021-12-31 03:56:59 【问题描述】:

在我下面的 PowerShell 中,我在 UNC 路径中获取所有第一级文件夹,并计算每个文件夹的文件、文件夹和大小(以 MB 为单位),我需要将其写入 SQL Server 表,但这在将值写入 SQL 字符串时让我有些头疼。

我有 3 个值需要写入 SQL,它们是:

$TotalFileCount $TotalDirectoryCount $TotalFolderSizeInMB'

我试着把它们写出来:

$TotalFileCount $($TotalFileCount) $($TotalFileCount.tostring() $($TotalFileCount.value.tostring())

但是当我创建Write-Host 时,它们都没有返回任何数据,所以我希望这是因为$TotalFileCount 是一个计算,但是任何找到解决方案来写出它的努力都是不费吹灰之力的,所以我需要一些帮助以找到解决方案。

我的 PS 脚本:

 $SQLServer = "SQL_SERVER"
 $SQLDatabase = "DATA_BASE"
    
    #SQL function
    function Invoke-SQL 
        param(
            [string] $sqlCommand = $(throw "Please specify a query.")
          )
    
        $connectionString = "Data Source=$SQLServer; " +
                "Integrated Security=SSPI; " +
                "Initial Catalog=$SQLDatabase"
    
        $connection = new-object system.data.SqlClient.SQLConnection($connectionString)
        $command = new-object system.data.sqlclient.sqlcommand($sqlCommand,$connection)
        $connection.Open()
        
        $adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
        $dataset = New-Object System.Data.DataSet
        
        $connection.Close()
        $dataSet.Tables
    
    
    Function Get-DirectoryTreeSize 
    
     
    [CmdletBinding(DefaultParameterSetName="Default")]
     
    param(
        [Parameter(
            Position = 0,
            Mandatory = $true
        )]
        [string]  $Path,
     
     
     
        [Parameter(
            Mandatory = $false,
            ParameterSetName = "ShowRecursive"
        )]
        [switch]  $Recurse,
     
     
     
        [Parameter(
            Mandatory = $false,
            ParameterSetName = "ShowTopFolderAllItemsAndAllFolders"
        )]
        [switch]  $AllItemsAndAllFolders
    )
     
        BEGIN 
            #Adding a trailing slash at the end of $path to make it consistent.
            if (-not $Path.EndsWith('\')) 
                $Path = "$Path\"
            
        
     
        PROCESS 
            try 
                if (-not $PSBoundParameters.ContainsKey("AllItemsAndAllFolders") -and -not $PSBoundParameters.ContainsKey("Recurse")) 
                    $FileStats = Get-ChildItem -Path $Path -File -ErrorAction Stop | Measure-Object -Property Length -Sum
                    $FileCount = $FileStats.Count
                    $DirectoryCount = Get-ChildItem -Path $Path -Directory | Measure-Object | select -ExpandProperty Count
                    $SizeMB =  "0:F3" -f ($FileStats.Sum / 1MB) -as [decimal]
     
                    [PSCustomObject]@
                        Path                 = $Path
                        FileCount            = $FileCount
                        DirectoryCount       = $DirectoryCount
                        FolderSizeInMB       = $SizeMB
                    
                
     
                if  ($PSBoundParameters.ContainsKey("AllItemsAndAllFolders")) 
                    $FileStats = Get-ChildItem -Path $Path -File -Recurse -ErrorAction Stop | Measure-Object -Property Length -Sum
                    $FileCount = $FileStats.Count
                    $DirectoryCount = Get-ChildItem -Path $Path -Directory -Recurse | Measure-Object | select -ExpandProperty Count
                    $SizeMB =  "0:F3" -f ($FileStats.Sum / 1MB) -as [decimal]
     
                    [PSCustomObject]@
                        Path                 = $Path
                        TotalFileCount       = $FileCount
                        TotalDirectoryCount  = $DirectoryCount
                        TotalFolderSizeInMB  = $SizeMB
                    
                
     
                if ($PSBoundParameters.ContainsKey("Recurse")) 
                    Get-DirectoryTreeSize -Path $Path
                    $FolderList = Get-ChildItem -Path $Path -Directory -Recurse | select -ExpandProperty FullName
     
                    if ($FolderList) 
                        foreach ($Folder in $FolderList) 
                            $FileStats = Get-ChildItem -Path $Folder -File | Measure-Object -Property Length -Sum
                            $FileCount = $FileStats.Count
                            $DirectoryCount = Get-ChildItem -Path $Folder -Directory | Measure-Object | select -ExpandProperty Count
                            $SizeMB =  "0:F3" -f ($FileStats.Sum / 1MB) -as [decimal]
     
                            [PSCustomObject]@
                                Path                 = $Folder
                                FileCount            = $FileCount
                                DirectoryCount       = $DirectoryCount
                                FolderSizeInMB       = $SizeMB
                            
                            #clearing variables
                            $null = $FileStats
                            $null = $FileCount
                            $null = $DirectoryCount
                            $null = $SizeMB
                        
                    
                
             catch 
                Write-Error $_.Exception.Message
            
     
        
     
        END 
     
    
    
    
    foreach ($name in Get-ChildItem "\\FILSRV01\home dir$"| Where  $_.PSIsContainer  | Where  $_.PSIsContainer  | Select-Object name)
    
        $TopPath = "\\FILSRV01\home dir$\"
    
        $TempPath = Join-Path $TopPath $name."name"
        
        Get-DirectoryTreeSize $TempPath -AllItemsAndAllFolders
    
   
        $sqlSelectCommand = "SELECT * from EFP_HomeFolder_Stats where UserInitials = '$($name."name")'"
        $sqlInsertCommand = "INSERT INTO EFP_HomeFolder_Stats (Path,UserInitials,TotalFileCount,TotalDirectoryCount,TotalFolderSizeInMB,LastUpdated) VALUES('$TempPath','$($name."name")','$($TotalFileCount)','$TotalDirectoryCount','$TotalFolderSizeInMB',GETDATE())"
        $sqlUpdateCommand = "UPDATE EFP_HomeFolder_Stats SET Path = '$TempPath', UserInitials = '$($name."name")', TotalFileCount = '$TotalFileCount', TotalDirectoryCount = '$TotalDirectoryCount', TotalFolderSizeInMB = '$TotalFolderSizeInMB', LastUpdated = GETDATE()"
    
        Invoke-SQL -sqlCommand $sqlSelectCommand
    
        Write-host $name.ExistCoun
    
    
        Invoke-SQL -sqlCommand "
    
            if exists ($sqlSelectCommand)            
            BEGIN            
                $sqlUpdateCommand
            End                    
            else            
            BEGIN
                $sqlInsertCommand
            END 
            "
    

【问题讨论】:

devblogs.microsoft.com/powershell/… 嗨@shawnt00 我可能正在监督有关您的链接的一些事情,但正如您在帖子中看到的那样,我已经尝试过了 可能是引号吗?有没有插入任何东西? 删除引号不会改变任何东西..在没有插入 SQL 的那一刻,我意识到了这一点,但想一次解决一个问题,我首先担心的是没有价值写出sql命令的时候写的。即INSERT INTO EFP_HomeFolder_Stats (Path,UserInitials,TotalFileCount,TotalDirectoryCount,TotalFolderSizeInMB,LastUpdated) VALUES('\\FILSRV01\home dir$\MWE','MWE',,,,GETDATE())UPDATE EFP_HomeFolder_Stats SET Path = '\\FILSRV01\home dir$\CAN', UserInitials = 'CAN', TotalFileCount = , TotalDirectoryCount = , TotalFolderSizeInMB = , LastUpdated = GETDATE() 两个 sql 语句中的计数都没有值。那肯定会出错。 【参考方案1】:

我现在已经解决了以下问题:通过将 Invoke-SQL 移动到 Get-DirectoryTreeSize 函数中,没有变量写入我的 SQL INSERT/UPDATE 查询,并且当我执行 Write-OutPut 时,值现在被填充到我的查询中的查询。我现在通过$MySplitPath = Split-Path -Path $Path -Leaf而不是$name."name" 获得的用户姓名首字母..

剩下的问题是 SQL 没有执行,这意味着没有任何东西被插入到我的 SQL 表中,所以我现在需要弄清楚这部分。如果有人有建议,我很乐意在这里提出建议:-)

#statiske vaiabler
$SQLServer = "SQL_SERVER"
$SQLDatabase = "SQL_DB"

#SQL function
function Invoke-SQL 
    param(
        [string] $sqlCommand = $(throw "Please specify a query.")
      )

    $connectionString = "Data Source=$SQLServer; " +
            "Integrated Security=SSPI; " +
            "Initial Catalog=$SQLDatabase"

    $connection = new-object system.data.SqlClient.SQLConnection($connectionString)
    $command = new-object system.data.sqlclient.sqlcommand($sqlCommand,$connection)
    $connection.Open()
    
    $adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
    $dataset = New-Object System.Data.DataSet
    
    $connection.Close()
    $dataSet.Tables


Function Get-DirectoryTreeSize 

 
[CmdletBinding(DefaultParameterSetName="Default")]
 
param(
    [Parameter(
        Position = 0,
        Mandatory = $true
    )]
    [string]  $Path,
 
 
 
    [Parameter(
        Mandatory = $false,
        ParameterSetName = "ShowRecursive"
    )]
    [switch]  $Recurse,
 
 
 
    [Parameter(
        Mandatory = $false,
        ParameterSetName = "ShowTopFolderAllItemsAndAllFolders"
    )]
    [switch]  $AllItemsAndAllFolders
)
 
    BEGIN 
        #Adding a trailing slash at the end of $path to make it consistent.
        if (-not $Path.EndsWith('\')) 
            $Path = "$Path\"

        
        if ($Path.EndsWith('\')) 
            $Path = "$Path\"

        
    
 
    PROCESS 
        try 
            if (-not $PSBoundParameters.ContainsKey("AllItemsAndAllFolders") -and -not $PSBoundParameters.ContainsKey("Recurse")) 
                $FileStats = Get-ChildItem -Path $Path -File -ErrorAction Stop | Measure-Object -Property Length -Sum
                $FileCount = $FileStats.Count
                $DirectoryCount = Get-ChildItem -Path $Path -Directory | Measure-Object | select -ExpandProperty Count
                $SizeMB =  "0:F3" -f ($FileStats.Sum / 1MB) -as [decimal]
 
                [PSCustomObject]@
                    Path                 = $Path
                    FileCount            = $FileCount
                    DirectoryCount       = $DirectoryCount
                    FolderSizeInMB       = $SizeMB
                
            
 
            if  ($PSBoundParameters.ContainsKey("AllItemsAndAllFolders")) 
                $FileStats = Get-ChildItem -Path $Path -File -Recurse -ErrorAction Stop | Measure-Object -Property Length -Sum
                $FileCount = $FileStats.Count
                $DirectoryCount = Get-ChildItem -Path $Path -Directory -Recurse | Measure-Object | select -ExpandProperty Count
                $SizeMB =  "0:F3" -f ($FileStats.Sum / 1024) -as [decimal]

                      $MySplitPath = Split-Path -Path $Path -Leaf  

                      Invoke-SQL -sqlCommand = "

                      IF EXISTS (SELECT * from EFP_HomeFolder_Stats where UserInitials = '$MySplitPath')
                      BEGIN
                        UPDATE EFP_HomeFolder_Stats SET UserInitials = '$MySplitPath', TotalFileCount = $FileStats.Count, TotalDirectoryCount = $DirectoryCount, TotalFolderSizeInMB = $SizeMB, LastUpdated = GETDATE()
                      END
                      ELSE
                      BEGIN
                        INSERT INTO EFP_HomeFolder_Stats (UserInitials,TotalFileCount,TotalDirectoryCount,TotalFolderSizeInMB,LastUpdated) VALUES('$MySplitPath',$FileStats.Count,$DirectoryCount,$SizeMB,GETDATE());
                      END
                                            
                      "

            
 
            if ($PSBoundParameters.ContainsKey("Recurse")) 
                Get-DirectoryTreeSize -Path $Path
                $FolderList = Get-ChildItem -Path $Path -Directory -Recurse | select -ExpandProperty FullName
 
                if ($FolderList) 
                    foreach ($Folder in $FolderList) 
                        $FileStats = Get-ChildItem -Path $Folder -File | Measure-Object -Property Length -Sum
                        $FileCount = $FileStats.Count
                        $DirectoryCount = Get-ChildItem -Path $Folder -Directory | Measure-Object | select -ExpandProperty Count
                        $SizeMB =  "0:F3" -f ($FileStats.Sum / 1MB) -as [decimal]
 
                        [PSCustomObject]@
                            Path                 = $Folder
                            FileCount            = $FileCount
                            DirectoryCount       = $DirectoryCount
                            FolderSizeInMB       = $SizeMB
                        
                        #clearing variables
                        $null = $FileStats
                        $null = $FileCount
                        $null = $DirectoryCount
                        $null = $SizeMB
                        

                    
                
            
         catch 
            Write-Error $_.Exception.Message
        
 
    

    END 
 




foreach ($name in Get-ChildItem "\\FILSRV01\home dir$"| Where  $_.PSIsContainer  | Where  $_.PSIsContainer  | Select-Object name)

    
    Write-Output $($null)
    
    $TopPath = "\\FILSRV01\home dir$\"

    $TempPath = Join-Path $TopPath $name."name"
    
    Get-DirectoryTreeSize $TempPath -AllItemsAndAllFolders


【讨论】:

以上是关于如何在 PowerShell 中将计算值写入 SQL INSERT/UPDATE的主要内容,如果未能解决你的问题,请参考以下文章

如何在powershell中将嵌套的任意关联数组值设置为.psd1文件?

如何在 C++14 中将多字节值写入共享内存?

在Powershell中将hashtable与循环中的类似值进行比较

从每个键具有多个值的字典中将数据写入 csv

PowerShell:如何在 PowerShell 中将数组对象转换为字符串?

Powershell写入第一行但无法将后续行写入for循环中的文件