使用Powershell读取Excel数据并写入变量

时间:2013-05-17 18:08:40

标签: excel powershell

使用PowerShell我想捕获用户输入,将输入与Excel电子表格中的数据进行比较,并将相应单元格中的数据写入变量。我是PowerShell的新手,似乎无法解决这个问题。例如:提示用户输入商店号码,输入“123”。然后将输入与A列中的数据进行比较。捕获相应单元格中的数据并将其写入变量,例如$ GoLiveDate。

非常感谢任何帮助。

示例数据:http://reddirttechnology.com/table.html

4 个答案:

答案 0 :(得分:12)

用户输入可以这样读:

$num = Read-Host "Store number"

Excel可以像这样处理:

$xl = New-Object -COM "Excel.Application"
$xl.Visible = $true
$wb = $xl.Workbooks.Open("C:\path\to\your.xlsx")
$ws = $wb.Sheets.Item(1)

在一列中查找值并将另一列中的相应值分配给变量可以这样做:

for ($i = 1; $i -le 3; $i++) {
  if ( $ws.Cells.Item($i, 1).Value -eq $num ) {
    $GoLiveDate = $ws.Cells.Item($i, 2).Value
    break
  }
}

完成后不要忘记clean up

$wb.Close()
$xl.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)

答案 1 :(得分:2)

我发现最好使用OleDB连接与Excel交互。它比COM互操作更快,并且比import-csv更不容易出错。您可以准备一组psobject(一个psobject是一行,每个属性对应一列)以匹配您想要的目标网格并将其插入Excel文件。类似地,您可以插入DataTable而不是PSObject集合,但除非您从某些数据源检索数据,否则PSObject集合方式通常更容易。

这是我用于将psobject集合写入Excel的函数:

function insert-OLEDBData ($file,$sheet,$ocol) {

    {
        "xlsb$" 
            {"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=`"$File`";Extended Properties=`"Excel 12.0;HDR=YES;IMEX=1`";"}
        "xlsx$"
            {"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=`"$File`";Extended Properties=`"Excel 12.0 Xml;HDR=YES;IMEX=1`";"}
    }
    $OLEDBCon = New-Object System.Data.OleDb.OleDbConnection($cs)

    $hdr = $oCol|gm -MemberType NoteProperty|%{$_.name}

    $names = '[' + ($hdr-join"],[") + ']'
    $vals = (@("?")*([array]$hdr).length)-join','

    $sql = "insert into [$sheet`$] ($names) values ($vals)"

    $sqlCmd = New-Object system.Data.OleDb.OleDbCommand($sql)
    $sqlCmd.connection = $oledbcon

    $cpary = @($null)*([array]$hdr).length

    $i=0
    [array]$hdr|%{([array]$cpary)[$i] = $sqlCmd.parameters.add($_,"VarChar",255);$i++}
    $oledbcon.open()

    for ($i=0;$i-lt([array]$ocol).length;$i++)
    {
        for ($k=0;$k-lt([array]$hdr).length;$k++)
        {
            ([array]$cpary)[$k].value = ([array]$oCol)[$i].(([array]$hdr)[$k])
        }
        $res = $sqlCmd.ExecuteNonQuery()
    }
    $OLEDBCon.close()

}

答案 2 :(得分:1)

我找到了这个,还有Yevgeniy的回答。我必须对上面的函数做一些小改动才能使它工作。最值得注意的是输入数组中的NULL或空值的处理。以下是Yevgeniy的代码,稍作修改:

function insert-OLEDBData {
    PARAM (
        [Parameter(Mandatory=$True,Position=1)]
        [string]$file,
        [Parameter(Mandatory=$True,Position=2)]
        [string]$sheet,
        [Parameter(Mandatory=$True,Position=3)]
        [array]$ocol
    )
    $cs = Switch -regex ($file)
    {
        "xlsb$"
            {"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=`"$File`";Extended Properties=`"Excel 12.0;HDR=YES`";"}
        "xlsx$"
            {"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=`"$File`";Extended Properties=`"Excel 12.0 Xml;HDR=YES`";"}
    }
    $OLEDBCon = New-Object System.Data.OleDb.OleDbConnection($cs)

    $hdr = $oCol | Get-Member -MemberType NoteProperty,Property | ForEach-Object {$_.name}

    $names = '[' + ($hdr -join "],[") + ']'
    $vals = (@("?")*([array]$hdr).length) -join ','

    $sql = "insert into [$sheet`$] ($names) values ($vals)"

    $sqlCmd = New-Object system.Data.OleDb.OleDbCommand($sql)
    $sqlCmd.connection = $oledbcon

    $cpary = @($null)*([array]$hdr).length

    $i=0
    [array]$hdr|%{([array]$cpary)[$i] = $sqlCmd.parameters.add($_,"VarChar",255);$i++}
    $oledbcon.open()

    for ($i=0;$i -lt ([array]$ocol).length;$i++)
    {
        for ($k=0;$k -lt ([array]$hdr).length;$k++)
        {
            IF (([array]$oCol)[$i].(([array]$hdr)[$k]) -notlike "") {
                ([array]$cpary)[$k].value = ([array]$oCol)[$i].(([array]$hdr)[$k])
            } ELSE {
                ([array]$cpary)[$k].value = ""
            }
        }
        $res = $sqlCmd.ExecuteNonQuery()
    }
    $OLEDBCon.close()
}   

答案 3 :(得分:1)

这似乎不再起作用。我发誓它曾经是,但是O365的更新也许杀死了它?或者我上一次在Win 7上使用它,并且已经移到Win 10了很久:

$GoLiveDate = $ws.Cells.Item($i, 2).Value

我仍然可以使用.Value写入单元格,但不能将其读取到变量中。而不是单元格的内容,它返回:“ Variant Value(Variant){get} {set}”

但是经过一番挖掘,我发现这样做确实可以将单元格读入变量:

$GoLiveDate = $ws.Cells.Item($i, 2).Text

关于下一个问题/评论squishy79询问缓慢性,以及随后的问题 OleDB解决方案,我似乎也无法在现代OS中使用这些解决方案,但是我自己的性能窍门是让我所有的Excel PowerShell脚本都写入制表符分隔的.txt文件,如下所示:

Add-Content -Path "C:\FileName.txt" -Value $Header1`t$Header2`t$Header3...
Add-Content -Path "C:\FileName.txt" -Value $Data1`t$Data2`t$Data3...
Add-Content -Path "C:\FileName.txt" -Value $Data4`t$Data5`t$Data6...

然后,在完成所有数据的写入后,使用非常慢的Com“ Excel.Application”打开.txt文件,然后再进行格式设置,然后执行SaveAs .xlsx(请参见SaveAs的注释):

Function OpenInExcelFormatSaveAsXlsx
{
    Param ($FilePath)
    If (Test-Path $FilePath)
    {
        $Excel = New-Object -ComObject Excel.Application
        $Excel.Visible = $true
        $Workbook = $Excel.Workbooks.Open($FilePath)
        $Sheet = $Workbook.ActiveSheet
        $UsedRange = $Sheet.UsedRange
        $RowMax = ($Sheet.UsedRange.Rows).count
        $ColMax = ($Sheet.UsedRange.Columns).count
        # This code gets the Alpha character for Columns, even for AA AB, etc.      
        For ($Col = 1; $Col -le $ColMax; $Col++)
        {
            $Asc = ""
            $Asc1 = ""
            $Asc2 = ""
            If ($Col -lt 27)
            {
                $Asc = ([char]($Col + 64))
                Write-Host "Asc: $Asc"
            }
            Else
            {
                $First = [math]::truncate($Col / 26)
                $Second = $Col - ($First * 26)
                If ($Second -eq 0)
                {
                    $First = ($First - 1)
                    $Second = 26
                }
                $Asc1 = ([char][int]($First + 64))
                $Asc2 = ([char][int]($Second + 64))
                $Asc = "$Asc1$Asc2"
            }
        }
        Write-Host "Col: $Col"
        Write-Host "Asc + 1: $Asc" + "1"
        $Range = $Sheet.Range("a1", "$Asc" + "1")
        $Range.Select() | Out-Null
        $Range.Font.Bold = $true
        $Range.Borders.Item(9).LineStyle = 1
        $Range.Borders.Item(9).Weight = 2
        $UsedRange = $Sheet.UsedRange
        $UsedRange.EntireColumn.AutoFit() | Out-Null
        $SavePath = $FilePath.Replace(".txt", ".xlsx")
        # I found scant documentation, but you need a file format 51 to save a .txt file as .xlsx
        $Workbook.SaveAs($SavePath, 51)
        $Workbook.Close
        $Excel.Quit()
    }
    Else
    {
        Write-Host "File Not Found: $FilePath"
    }
}

$TextFilePath = "C:\ITUtilities\MyTabDelimitedTextFile.txt"
OpenInExcelFormatSaveAsXlsx -FilePath $TextFilePath

如果您不关心格式,则可以按原样在Excel中打开制表符分隔的.txt文件。 当然,这对于将数据插入到现有的Excel电子表格中不是很好,除非您可以让脚本在每次插入时重写整个工作表。在大多数情况下,它的运行速度仍比使用COM快得多。