Author Posts

April 13, 2015 at 6:08 am

In my SCCM task sequence i'm trying to get the values of the ZTIGather and put the option that comes back true to a variable. So far i can get a result list of 'false, false and true' Which tells me its working. Just not sure how i can get out the "$true" value.

$TSEnv = New-Object -ComObject Microsoft.SMS.TSEnvironment

$Type = @{ "Desktop" = $Desktop = ('IsDesktop')
"Laptop" = $Laptop = ('IsLaptop')
"VM" = $VM = ('IsVM')
}

foreach ($Model in $Type.Values)
{($TSEnv.value($Model))}

Can anyone help ?

April 13, 2015 at 6:53 am

You probably want to generate an object with the results:

$TSEnv = New-Object -ComObject Microsoft.SMS.TSEnvironment
$models = "IsDesktop", "IsLaptop", "IsVM" | foreach{
    New-Object -TypeName PSObject -Property @{"TSVariable"=$_;"Value"=$($TSEnv.value($_))}
}

$models | Where{$_.Value -eq "True"}

What you need to understand is that the values are strings, not Boolean values (e.g. $true\$false). If you wanted to convert them to Boolean values (http://www.jonathanmedd.net/2012/05/powershell-quick-tip-converting-a-string-to-a-boolean-value.html), then you could use $true for comparison:

$TSEnv = New-Object -ComObject Microsoft.SMS.TSEnvironment
$models = "IsDesktop", "IsLaptop", "IsVM" | foreach{
    New-Object -TypeName PSObject -Property @{"TSVariable"=$_;"Value"=$([System.Convert]::ToBoolean($TSEnv.value($_)))}
}

$models | Where{$_.Value -eq $true}

I didn't test this, but it should get you in the right direction.

April 13, 2015 at 6:58 am

Thank you Rob. Been banging my head against a brick wall.

I was so far off the correct script 🙁

April 13, 2015 at 7:01 am

Would you be able to break it down to help me understand please Rob ?

April 13, 2015 at 8:04 am

Let's take the TS stuff out of the equation.

#$TSEnv = New-Object -ComObject Microsoft.SMS.TSEnvironment

#loop through the 3 varaibles and assign the output of the loop to $models
$models = "IsDesktop", "IsLaptop", "IsVM" | foreach{
    #Create a new object with the property TSVariable and Value that is being returned to $models
    #In the Value, we take a string value and convert it to boolean
    New-Object -TypeName PSObject -Property @{"TSVariable"=$_;"Value"="True"}
}

No matter if it's a string or a Boolean value, your output would look like this:

Value TSVariable
—– ———-
True IsDesktop
True IsLaptop
True IsVM

However, if you look deeper, if we do the conversion to Boolean, we'll see this:

PS C:\Users\rsimmers> $models[0].Value.GetType()

IsPublic IsSerial Name                                     BaseType                                                                                               
-------- -------- ----                                     --------                                                                                               
True     True     Boolean                                  System.ValueType     

If we change the line to

New-Object -TypeName PSObject -Property @{"TSVariable"=$_;"Value"="True"}

Now, True is a string.

PS C:\Users\rsimmers> $models[0].Value.GetType()

IsPublic IsSerial Name                                     BaseType                                                                                               
-------- -------- ----                                     --------                                                                                               
True     True     String                                   System.Object      

At this point, you are doing string comparison, so checking if a string is a boolean value could give false-positive results. If you read through the article link, "This is because PowerShell will convert any string greater than 0 characters to a Boolean 'true'" You either have to test string to string, or boolean to boolean. Anything else is going to provide inconsistent results, especially across Powershell versions. It's better to cast or force the variable to the data type than assume Powershell is going to convert it for you. If you read some Powershell books, Powershell does do some automatic conversions, but there are rules:

#This is basically just string concatenation, put these strings together.  If you are wrapping single or double quotes around it,  basically you saying it's a string...
PS C:\Users\rsimmers> "10" + "30"
1030
#The first item takes precedence, so even though 30 is last, Powershell converts it to a string because the string preceded it
PS C:\Users\rsimmers> "10" + 30
1030
#This is casting, basically saying that I want the data type to be an integer, now Powershell does the math
PS C:\Users\rsimmers> [int]"10" + 30
40
# To the earlier point, an integer preceded the string, so Powershell converts the next number to a integer
PS C:\Users\rsimmers> 30 + "30"
60

Understanding data types and what commands are expecting is integral to using Powershell. Passing a string when a command expects an integer could cause issue and when you see "Type Mismatch", that is basically saying you passed me something that is not was is defined. You passed me a letter and I expected a number. Hopefully this makes sense.

April 13, 2015 at 8:25 am

Thanks Rob.

New-Object -TypeName PSObject -Property @{"TSVariable"=$_;"Value"="True"}
}

Can you explain what is gong in in the {} please ?

April 13, 2015 at 8:47 am

It is a hash table. If you do "Get-Help New-Object", you will see that the -Property parameter is looking for IDictionary, which is base object of Hashtable. Back in vbScript days, we used the Dictionary object which basically was a key and a value to store data. There are several ways to create them like:

PS C:\Users\rsimmers> $iDictionary = @{}

PS C:\Users\rsimmers> $iDictionary.Add("MyColumn","MyValue")

PS C:\Users\rsimmers> $iDictionary.GetType()

IsPublic IsSerial Name                                     BaseType                                                                                               
-------- -------- ----                                     --------                                                                                               
True     True     Hashtable                                System.Object                                                                                          

or short-hand like so:


PS C:\Users\rsimmers> $iDictionary2 = @{"MyColumn"="MyValue"}

PS C:\Users\rsimmers> $iDictionary2.GetType()

IsPublic IsSerial Name                                     BaseType                                                                                               
-------- -------- ----                                     --------                                                                                               
True     True     Hashtable                                System.Object   

They can get more complicated with nested tables, but basically we are defining the column (key) and the value assoicated with that column (key). In short-hand, semicolon (;) represents the end of a line to place multiple key\values in on step. If you have not yet, you need to really pick up the Month of Lunches book by Don and try to get a good foundation on these concepts.

April 13, 2015 at 8:52 am

Awesome, thank you so much. Very much appreciated.

April 15, 2015 at 3:23 am

I hope someone can help as this is driving me crazy !

I'm trying to, from Rob's brilliant script, just output the model. So, if for example i run it on a desktop i want it to come back with, if IsDesktop is true, just display "IsDesktop".

I've been trying all sorts and i can't work it out ! problably some clever dude knows how i can already !

Thanks.

April 15, 2015 at 4:04 am

$models | Where {$_.Value -eq $true} | Select -ExpandProperty TSVariable

April 15, 2015 at 5:12 am

Thanks Rob, so easy when you know how ! I've been trying all sorts !

April 15, 2015 at 5:34 am

The way those variables are designed is that you would have a group of items in the TS that would be run if IsVM = True. Something like this:
IsLaptop = True
Install VPN Software
Script for a laptop

IsVM = True
Install VM tools
Disable unnecessary services
Script for a VM

However, if you wanted to use a single script to configure these services, you should modularize the code and make a function to get the variable. Here is an idea of how I would do it (not tested):


function Get-TSModel {
    param()
    begin{
        $TSEnv = New-Object -ComObject Microsoft.SMS.TSEnvironment
    } #begin
    process{
        #loop through the 3 varaibles and assign the output of the loop to $models
        $models = "IsDesktop", "IsLaptop", "IsVM" | foreach{
            #Create a new object with the property TSVariable and Value that is being returned to $models
            #In the Value, we take a string value and convert it to boolean
            New-Object -TypeName PSObject -Property @{"TSVariable"=($_ -replace "Is", "");"Value"=$([System.Convert]::ToBoolean($TSEnv.value($_)))}

            $modelType = $models | Where {$_.Value -eq $True} | Select -ExpandProperty TSVariable
        } #models foreach
    }#process
    end {
        $modelType
    }#end
}#function Get-TSModel



switch (Get-TSModel) {
    "Desktop" {
        #Stuff for desktops
    }
    "Laptop" {
        #Stuff for laptops
    }
    "VM" {
        #Stuff for VMs
    }
}

April 15, 2015 at 6:01 am

Again, thank you Rob. I'm running the script in SCCM so it will populate $tsenv.value("ModelType") with either IsVM, IsDesktop or IsLaptop. Then i can use a Task Sequence variable in against the various apps (i.e. wireless profile) for model type.

For me its and excuse to learn PowerShell while working ! The more i do the more i hope it will help me learn.

That script is very cool....