Powershell String Splitting discrepency

12,955

Solution 1

I was able to fix my problem by verifying that the specified argument was a string. If it was already an array, then it was just passed to the function. This is checked like so:

if($servers -is [system.string]){
        $servers = $servers.split(',')
}

Solution 2

For whatever reason, $varname contains an array when you run it in a script. And there is no Split method on an array. Can you show the script where you determine the value assigned to $varname? BTW if the array contains a string you want to split, try this $varname[0].Split(',').

Share:
12,955
nlowe
Author by

nlowe

Linux and Open Source enthusiast. I also like technical theater! Opinions are my own.

Updated on June 04, 2022

Comments

  • nlowe
    nlowe almost 2 years

    I am trying to split a string in PowerShell by calling $varname.split(','). This works fine when I am in a PowerShell console, but not when I invoke the script directly.

    From the Command Prompt: powershell .\scriptname.ps1

    Method invocation failed because [System.Object[]] doesn't contain a method named 'split'.
    At C:\scriptname.ps1:92 char:30
    +         reboot $varname.split <<<< (',')
        + CategoryInfo          : InvalidOperation: (split:String) [], RuntimeException
        + FullyQualifiedErrorId : MethodNotFound
    

    Again, this works perfectly fine when I run it in the ISE or directly from a PS prompt. Thoughts?

    Edit: I've provided my script below. I'm sort of new to powershell, so I don't see anything that would cause a variable to behave as an array only when called through the commandline.

    [string]$servers
    [string]$filepath
    [string]$account  = $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)
    [string]$mode
    [bool]  $reboot   = $FALSE
    
    Write-Host "========================================"
    Write-Host "| Windows Server Shutdown Utility v1.0 |"
    Write-Host "========================================"
    
    Function usage(){
        Write-Host "Arguments are accepted in any order as long as the data follows the mode."
        Write-Host "<required> [optional]"
        Write-Host "Usage: powershell .\wss.ps1 <-l|-f> <data> [-account] [-reboot] [--help]"
        Write-Host "`tModes"
        Write-Host "`t`t-list: A list of servers, seperated by commas with no spaces inbetween"
        Write-Host "`t`t`tAliases: -l"
        Write-Host "`t`t`t[*] Example: `"ServerA.domain,ServerB.domain`""
        Write-Host "`t`t-file: A path to a file that contains one server name on each line"
        Write-Host "`t`t`tAliases: -f"
        Write-Host "`t`t`t[*] Example: `"C:\allDomainServers.txt`""
        Write-Host "`taccount: The domain and account to use. You will be prompted for a password."
        Write-Host "`t`t`tAliases: -a, -ac"
        Write-Host "`treboot: If specified, the servers will be shutdown instead of rebooted."
        Write-Host "`t`t`tAliases: -r"
        Write-Host "`thelp: Prints the help screen."
        Write-Host "`t`t`tAliases: -h, -help, /help, /?"
        Write-Host "`t`tNOTE: If no account is specified, the current user will be used."
    
    }
    
    Function shutdown($arr){
        $arr | ForEach{
            Write-Host "Attempting to shutdown $_"
            Stop-Computer -computername ($_) -credential ($c) -force
        }
        Write-Host "Finished. Please be aware that some servers may still be in the process of shutting down."
    }
    
    Function reboot($arr){
        $arr | ForEach{
            Write-Host "Attempting to reboot $_"
            Restart-Computer -computername ($_) -credential ($c) -force
        }
        Write-Host "Finished. Please be aware that some servers may still be in the process of rebooting."
    }
    
    #Parse Arguments
    if($args.length -eq 0 -or $args[0] -eq "-help" -or $args[0] -eq "/help" -or $args[0] -eq "--help" -or $args[0] -eq "/?"){
       usage
       exit
    }
    
    for($i=0; $i -lt $args.length; $i++){
        $k = $args[$i]
        if($k -eq "-r" -or $k -eq "-reboot"){
            $reboot = $TRUE
        }elseif($k -eq "-a" -or $k -eq "-ac" -or $k -eq "-account"){
            $account = $args[++$i]
        }elseif((!$mode) -and ($k -eq "-l" -or $k -eq "-list")){
            $servers = $args[++$i]
            $mode    = "list"
        }elseif((!$mode) -and ($k -eq "-f" -or $k -eq "-file")){
            $filepath = $args[++$i]
            $mode     = "file"
        }
    }
    
    #Verify Account Credentials
    $c = get-credential $account
    
    if(!$c){
        Write-Host "No credentials specified!"
        exit
    }
    
    if($mode -eq "list"){
        Write-Host "Using Mode: List"
        if([string]::IsNullOrEmpty($servers)){
            usage
            exit
        }
    
        if($reboot){
            reboot $servers.split(',')
        }else{
            shutdown $servers.split(',')
        }
    
    }elseif($mode -eq "file"){
        Write-Host "Using Mode: File"
        if([string]::IsNullOrEmpty($filepath)){
            $filepath = Read-Host 'Enter the path to the file containing a list of hosts:'
        } 
    
        if(!(Test-Path $filepath)){
            Write-Host "Error! File doesn't exist!"
            exit
        }
    
        if($reboot){
            reboot (get-content $filepath)
        }else{
            shutdown (get-content $filepath)
        }
    
    }else{
        Write-Host "Unknown Mode! Got: $mode"
        exit
    }
    

    Edit 2: See further testing using this script:

    for($i=0; $i -lt $args.length; $i++){
        Write-Host $args[$i]
        Write-Host $args[$i].GetType()
    }
    

    Powershell Prompt:

    PS C:\> .\test.ps1 asdf fdsa
    asdf
    System.String
    fdsa
    System.String
    
    PS C:\> .\test.ps1 "asdf,fdas"
    asdf,fdas
    System.String
    
    PS C:\> .\test.ps1 "asdf","fdas"
    asdf fdas
    System.Object[]
    
    PS C:\> .\test.ps1 asdf,fdas
    asdf fdas
    System.Object[]
    

    Command Prompt:

    C:\>powershell .\test.ps1 asdf fdsa
    asdf
    System.String
    fdsa
    System.String
    
    C:\>powershell .\test.ps1 "asdf,fdas"
    asdf fdas
    System.Object[]
    
    C:\>powershell .\test.ps1 "asdf","asdfa"
    asdf asdfa
    System.Object[]
    
    C:\>powershell .\test.ps1 asdf,fdas
    asdf fdas
    System.Object[]
    

    Notice the difference between how it treats quoted strings (test # 2). Why is this happening? And is there any way around this?