简体   繁体   中英

Issues using Set-Variable to set sub values (ex. $Myvar.item.value) in loop

I am working on a script that outputs about 600 variables across several dozen worksheets and it takes up about 500 lines of code just to add the column headers to each of the worksheets. In an effort to reduce the immense amount of overall code I am trying to put the action of creating the column headers to a function but for some reason set-variable won't set the value. It only gives me an error when I try and set sub values in the item.

This returns the following error

Function PopulateWorkSheet($Worksheet,$Values) {
    ForEach ($Value in $Values) {
        $ColumnCount++
        Set-Variable -Name $($Worksheet).Cells.Items(1,$ColumnCount) -value $Value
    }
    Remove-Variable -Name ColumnCount
}

Error

You cannot call a method on a null-valued expression.
At line:4 char:30
+         Set-Variable -Name $($Worksheet).Cells.Items(1,$ColumnCount) -value $Val ...
+                              ~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

But this doesn't return an error.

Function PopulateWorkSheet($Worksheet,$Values) {
    ForEach ($Value in $Values) {
        $ColumnCount++
        Set-Variable -Name $($Worksheet) -value $Value
    }
    Remove-Variable -Name ColumnCount
}

My Full Code

Function PopulateWorkSheet($Worksheet,$Values) {
    ForEach ($Value in $Values) {
        $ColumnCount++
        Set-Variable -Name $($Worksheet).Cells.Items(1,$ColumnCount) -value $Value
    }
    Remove-Variable -Name ColumnCount
}

clear
#Create Excel Com Object
$Excel = New-Object -com Excel.Application

# Make the Excel Application Visible to the end user
$Excel.visible = $True

# Create a WorkBook inside the Excel application
# that we can start manipulating.
$Excel_Workbook = $Excel.Workbooks.Add()

#=======================================================
# Now that we have a workbook we need to create some
# additional worksheets (Tabs) beyond that initial 3
# that are created when the workbook is opened.
#=======================================================
$Temp_MakeWorkSheet = $Excel.Worksheets.Add()

#=======================================================
# Once all the sheets are created each of the worksheets
# need to be assigned to a variable so they can be
# manipulated.
#=======================================================
$Excel_Worksheet_SystemSummary = $Excel.Worksheets.Item(1)
$Excel_Worksheet_SystemSummary.Name = "System Summary"

#=======================================================
# = System Summary = Create Table Headers
#=======================================================

PopulateWorkSheet -Worksheet Excel_Worksheet_SystemSummary -value @("Computer Name","Serial Number","Operating System","Service Pack","OS Architecture","Part of Domain","Domain Role","System Uptime","IP Address","OS HD Smarts Check","# of Mice","# of Keyboards","# of Hard Drives","# of CD/DVD Drives","# of Network Adapters")

Why do you think you need to use Set-Variable at all? Set-Variable is for setting Powershell variables when you don't know the name in advance, or when you want to do special things like making them read-only. In this case you don't want to set a Powershell variable at all, you want to set the value of a cell in a worksheet.

So forget Set-Variable . Also forget Remove-Variable : returning from a function removes all the local variables anyway, you don't have to do it yourself.

$Worksheet , if I read your code correctly is simply a reference to the worksheet. So why did you write $($Worksheet) ? That doesn't actually do anything that just writing $Worksheet wouldn't have done on its own.

Now consider $Worksheet.Cells.Items(1,$ColumnCount) . The first two elements won't change inside your loop, so hoist them out of the loop. Now you should have something like:

Function PopulateWorkSheet($Worksheet,$Values) {
    $cells = $Worksheet.Cells
    $ColumnCount = 0
    ForEach ($Value in $Values) {
        $ColumnCount++
        $cells.Item(1,$ColumnCount) = $Value
    }
}

This also works:

Function PopulateWorkSheet($Worksheet,$Values) {
    $Worksheet.Range(
        $Worksheet.Cells.Item(1,1),
        $Worksheet.Cells.Item(1,$Values.Count)).value() = $Values
}

and will assign the complete list in one go.

Instead of

Set-Variable -Name $($Worksheet).Cells.Items(1,$ColumnCount) -value $Value

Try

$var=Get-Variable -Name $($Worksheet)
$var.Cells.Items(1,$ColumnCount)=$Value

Note...I haven't tried this, but there's no reason it shouldn't work.

So I was way overthinking it. I did not need to try and load the variable in the function, but pass value to the "Worksheet" variable since the $Excel_Worksheet_SystemSummary is just a link to the cell contents, and it doesn't actually hold any real information.

Function PopulateWorkSheet($Worksheet,$Values) {
    ForEach ($Value in $Values) {
        $ColumnCount++
        $worksheet.Cells.Item(1,$ColumnCount)=$Value
    }
    Remove-Variable -Name ColumnCount
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM