Thijsk1
Thijsk1

Reputation: 33

Powershell import csv with $true and $false

I am trying to learn how to import a csv in Powershell and create users out of it. One of the values I need to import needs to be converted to a boolean. These values will only be $true or false.

My current code is

param([Parameter(Mandatory)][string] $inputfile)

$ADUsers = Import-csv $inputfile -Delimiter ';'

foreach ($User in $ADUsers) {
    $Name = $User.Name
    $SurName = $User.sn
    $GivenName = $User.Givenname
    $Email = $User.Email
    $SamAccountName = $User.samAccount
    $Path = $User.ParentOU
    $Password = $User.Password
    $Enabled = [System.Convert]::ToBoolean($User.Enabled)
    $ChangePasswordAtLogon = [System.Convert]::ToBoolean($User.mustChangePassword)
    $Description = $User.Description
    
    New-ADUser `
        -Name = $Name `
        -Surname =  $SurName `
        -GivenName = $GivenName `
        -EmailAddress = $Email `
        -SamAccountName = $SamAccountName `
        -Path = $Path `
        -AccountPassword (ConvertTo-SecureString $Password -AsPlainText -Force) `
        -Enabled = $Enabled `
        -ChangePasswordAtLogon = $ChangePasswordAtLogon `
        -Description = $Description
}

With the current code, my only problem (currently) seems to be I am unable to parse this string to a boolean. The error: Exception calling "ToBoolean" with "1" argument(s): "String was not recognized as a valid Boolean."

Anyone who knows the best way to resolve this issue?

Upvotes: 1

Views: 2091

Answers (2)

mklement0
mklement0

Reputation: 439247

Theo's helpful answer provides an effective, streamlined solution; let me add some background information:

  • The property values of the objects created from CSV data by Import-Csv are invariably strings (i.e. of type [string]).

  • You fundamentally cannot pass [string] values to [bool] or [switch] parameters - even if those string values are 'True' and 'False'.

    • The simplest way to convert these values to [bool] is [bool]::Parse($stringContainingTrueOrFalse) (case does not matter, and the conversion works irrespective of what culture is in effect).
  • [bool] parameters, which are rare, unlike the much more common [switch] parameters (see below), accept numbers too: 0 converts to $false, and any non-zero number to $true.

  • [switch] parameters only accept actual [bool] values, though note that they rarely require an explicit argument, because it is their presence or absence that implies their value; e.g., -Force is the same as -Force:$true (note the need to follow the parameter name with : in this case); and not specifying -Force is (typically) the same as
    -Force:$false; there are only two scenarios in which passing an explicit argument is needed:

    • To pass a switch programmatically, via a variable (e.g., -Force:$value)
    • To override a preference variable (e.g. -Confirm:$false to skip a confirmation prompt that would otherwise be shown based on the value of the $ConfirmPreference preference variable); in this specific case passing $false as an explicit argument does more than omitting the switch altogether would do.

Note:

The above applies to parameter binding.
By contrast, in expression contexts strings (and other objects) can be cast or coerced to [bool], though the behavior can be surprising:

  • An empty string evaluates to $false, whereas any non-empty string is $true, i.e. irrespective of its specific content.

Notably:

PS> [bool] 'False'
True # !! Evaluates to $true, because 'False' is a *non-empty* string.

In general, though, this behavior is helpful, as it allows you to use strings directly as conditionals; the following statements are equivalent:

if ($string.Length -gt 0) { 'non-empty' }

# Equivalent shorthand
if ($string) { 'non-empty' }

See the bottom section of this answer for an overview of PowerShell's implicit to-Boolean conversion across all types.


Pitfall, as of PowerShell 7.2:

While a casting a string to [bool] works as shown above, a [bool] variable type constraint unexpectedly behaves like a parameter declaration:

That is, while you would expect $var = [bool] 'foo' to work the same as [bool] $var = 'foo' (aside from the latter locking the variably type in), the latter fails:

PS> $var = [bool] 'foo'  # OK: stores $true in $var

PS> [bool] $var =  'foo'  # !! FAILS
... Cannot convert value "System.String" to type "System.Boolean".
Boolean parameters accept only Boolean values and numbers, such as $True, $False, 1 or 0.

This problematic asymmetry is discussed in GitHub issue #10426.

Upvotes: 1

Theo
Theo

Reputation: 61168

If the CSV contains string values for Enabled and ChangePasswordAtLogon literally as '$true' or '$false', you need to remove the dollar sign from it to be able to convert them into real Boolean values.

Also, I would suggest using Splatting the parameters to New-ADUser, so you can get rid of all those unneeded extra variables and especially those pesky backticks:

param([Parameter(Mandatory)][string] $inputfile)

$ADUsers = Import-Csv -Path $inputfile -Delimiter ';'

foreach ($User in $ADUsers) {
    $userParams = @{
        Name                  = $User.Name
        Surname               = $User.sn
        GivenName             = $User.Givenname
        EmailAddress          = $User.Email
        SamAccountName        = $User.samAccount
        Path                  = $User.ParentOU
        AccountPassword       = (ConvertTo-SecureString $User.Password -AsPlainText -Force)
        Description           = $User.Description
        # if these values in the CSV are '$true' or '$false' literally, remove the dollar sign
        Enabled               = [System.Convert]::ToBoolean($User.Enabled -replace '\$')
        ChangePasswordAtLogon = [System.Convert]::ToBoolean($User.mustChangePassword -replace '\$')
    }

    New-ADUser @userParams
}

Upvotes: 3

Related Questions