none
How to Split values by delimiters? RRS feed

  • Question

  • I have a script that has a switch, -Add, allowing the addition of 1 role and 1 member (into that role) in a database at a time.

    PS> script1.ps1 -Add Database1 role1 member1
    PS> script1.ps1 -Add Database1 role1 member2
    PS> script1.ps1 -Add Database1 role2 memberx
    PS> script1.ps1 -Add Database1 role3
    PS> script1.ps1 -Add Database1 role4 membery

    It wont be practical to have to run that script everytime if there are more than 1 member or 1 roles/members to add a time. hence, i'd like to update my script with bulk addition of roles/members at once, which would be helpful especially for a TFS use case, in which the user wont have to create multiple releases just to add a couple roles/members for the same database.

    i am thinking of implementing a delimiter split, in which for every semicolon, that indicates the start of a new role, and any comma delimited members, all belong to one role unless a semicolon follows (not necessary if its the end of the input, unless it would be hard to achieve something like that with regex?)

    pseudocode:

    $RoleInput.Split(";") | ForEach { 
    
        $role = "$_";
    
        $MemberInput.Split(",") | ForEach { 
    
            $member = "$_";
    
            #-Add $DBName $role $member
    
        }
    }

    ultimately, i would like to achieve similar to the following:

    PS> script1.ps1 -Add Database1 role1;role2;role3;role4 member1,member2;memberx;;membery

    this means that for role1, member1 and member2 would be added for role2, memberx is addedfor role3, no member is added, and for role 4, membery is added

    how would i achieve this correctly with regex to account for whitespaces, and end of input?

    -----

    I asked this elsewhere, but havent received compelling suggestions within the limits of the requirement/use case i am bound by as I had hoped. 

    https://stackoverflow.com/questions/57261910/how-to-combine-and-split-values-by-delimiter



    • Edited by cataster Tuesday, July 30, 2019 3:09 PM
    Tuesday, July 30, 2019 3:05 PM

All replies

  • The reason you are not receiving answers is because your question doesn't make any sense and is missing all useful information that would make it make sense.

    Start by reading this and try again:  How to ask questions in a technical forum


    \_(ツ)_/

    Tuesday, July 30, 2019 3:14 PM
    Moderator
  • The reason you are not receiving answers is because your question doesn't make any sense and is missing all useful information that would make it make sense.

    Start by reading this and try again:  How to ask questions in a technical forum


    \_(ツ)_/

    i actually received a close enough answer, and i was discussing with Lee_dailey/Ansgar possible approaches to this. the approaches they proposed are correct but they dont apply to my certain use case, in which i cant build a frontend UI interface nor allow CSV file input, or JSON because the only thing i have available is TFS release and the input allowed is just a delimited string somehow. in the JSON case, users are not technical so i cant use JSON as input since users wont know how to enter something like that. 

    Neither Lee nor Ansgar seemed confused/faced ambiguity by the question, so it appears to be straight forward :)

    is there something you'd like me to emphasize more on that would help in a potential answer?

     
    Tuesday, July 30, 2019 3:19 PM
  • The nearest guess would be the following but it is a guess about what you are trying to ask.

    $array = @(
        @('role1', 'member1'),
        @('role2', 'member2'),
        @('role3', 'member3'),
        @('role4', 'member4')
    )
    foreach($item in $array){
        script1.ps1 -Add Database1 $item[0] $item[1]
    }
    


    \_(ツ)_/

    Tuesday, July 30, 2019 3:20 PM
    Moderator
  • To turn a string into an array:

    $roles = 'role1,role2,role3' -split ','


    \_(ツ)_/

    Tuesday, July 30, 2019 3:23 PM
    Moderator
  • The nearest guess would be the following but it is a guess about what you are trying to ask.

    $array = @(
        @('role1', 'member1'),
        @('role2', 'member2'),
        @('role3', 'member3'),
        @('role4', 'member4')
    )
    foreach($item in $array){
        script1.ps1 -Add Database1 $item[0] $item[1]
    }


    \_(ツ)_/

    this is actually pretty close to what i want. 

    just to explain further, that array would be (by some splitting/parsing process) generated by an input like this:

    -Add Database1 role1;role2;role3;role4 member1;member2;member3;member4

    now i would like to consider inputs like this:

    -Add Database1 role1;role2;role3;role4 member1,member2;;member3;member4

    then the array would be:

    $array = @(
        @('role1', 'member1,member2'),
        @('role2', ''),
        @('role3', 'member3'),
        @('role4', 'member4')
    )

    Tuesday, July 30, 2019 3:26 PM
  • Also to send an array on a powershell line we do this:

    script1.ps1 -Add -DataBase Database1 -Roles role1,role2,role3,role4 -Members member1,member2,member,membery

    The Param statement would look like this:

    Param(
         $DataBase,
         [string[]]$Roles,
         [string[]]$Members,
         [switch]$Add
    }
         


    \_(ツ)_/



    Tuesday, July 30, 2019 3:28 PM
    Moderator
  • Also to send an array on a powershell line we do this:

    script1.ps1 -Add -DataBase Database1 -Roles role1,role2,role3,role4 -Members member1,member2,member,membery

    The Param statement would look like this:

    Param(
         $DataBase,
         [string[]]$Roles,
         [string[]]$Members,
         [switch]$Add
    }
         


    \_(ツ)_/



    yep, so this one considers a use case that adds 1 member to 1 role. now imagine use cases where a user wants to add more than 1 member to a role, or just add a role without any member. 

     inputs like this:

    -Add Database1 role1;role2;role3;role4 member1,member2;;member3;member4

    then the array would be:

    $array = @(
        @('role1', 'member1,member2'),
        @('role2', ''),
        @('role3', 'member3'),
        @('role4', 'member4')
    )

    so for every semicolon, that indicates start of a new index for a role. and a semicolon for member would indicate allocate the member afte rthe semicolon (if there is), to the corresponding role index

    Tuesday, July 30, 2019 3:37 PM


  • yep, so this one considers a use case that adds 1 member to 1 role. now imagine use cases where a user wants to add more than 1 member to a role, or just add a role without any member. 

     inputs like this:

    -Add Database1 role1;role2;role3;role4 member1,member2;;member3;member4

    then the array would be:

    $array = @(
        @('role1', 'member1,member2'),
        @('role2', ''),
        @('role3', 'member3'),
        @('role4', 'member4')
    )

    so for every semicolon, that indicates start of a new index for a role. and a semicolon for member would indicate allocate the member afte rthe semicolon (if there is), to the corresponding role index

    We have no idea what is in your script and no idea what you are trying to do.  So far it is just disjoint information. 

    What is in "script1.ps1".  It appears to be non-existent.  This makes answering or understanding what you want nearly impossible.

    I have shown you how to split a string.  If you want input from a file I recommend a CSV file.

    First take some time to learn basic PowerShell programming so you will be able to describe what you are trying to do.  ALso please read the link I posted above.


    \_(ツ)_/

    Tuesday, July 30, 2019 3:50 PM
    Moderator
  • Another reason for learning basic PowerShell is that you cannot use semicolons on a command line.  They break the command line.

    You have to define a data method for your script.  You also have to learn if your database calls can work with arrays and strings.  This depends on what database calls your are using.  If SQLServer then SMO can do this with much elss screwing around.


    \_(ツ)_/

    Tuesday, July 30, 2019 3:55 PM
    Moderator
  • Maybe restructuring your script1.ps1 file to be a module would make more sense?  If so, then you can use the pipeline feature of powershell to send the list to your cmdlet and use the begin/process/end features.

    So for example, save this to a *.psm1 file (a module file):

    function DoStuff{

    param( [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)] $stuffToDo ) begin { #for clarity, create a new variable at function level, so it can be seen and used througout. $dbConn # we'll track the 'current' db here for later comparison and possible need to change. $currentDB # this variable will be incremented for each pipeline object that is processed. for tracking/reporting $counter = 0 #setup database connection into variable #we'll initialize the connectio to the specific database in our input variable... $currentDB = $stuffToDo.DB $dbConn = get-SomeDBConnection -database $currentDB } process{ # check to see if we are changing to a different database by comparing the DB prop to our 'current' one. if ($stuffToDo.DB -ne $currentDB) { # do any clean up/release, assuming such is needed. $dbConn.Close() $currentDB = $stuffToDo.DB $dbConn = get-SomeDBConnection -database $currentDB } # this call is called for the single element of the list from the pipeline $dbConn.AddToDB($stuffToDo.DB, $stuffToDo.role, $stuffToDo.members) } end { # do last clean up of resources, assuming such is needed. $dbConn.Close() } }



    Then, from powershell you can do:  Import-Module .\path\to\script1.psm1

    For the input, if you used a hashtable, you wouldn't have to do any parsing.  example:

    # this will create a list of hashtables, with each having a DB, role, and members property.
    # the 'members' property is a list/array of member names, in case you wanted to add several members to one role.
    # with this, you could fairly easily create this list of hashtables from a CSV import or other source.
    # we store the database name with each 'record' so that the script can change to a different database on the fly.
    $userRoles = @{"DB"="database1"; "role"="role1"; "members"="member1","member2"},@{"DB"="database1", "role"="role2"; "members"="member1","member3"}
    


    after import, you can simply call your cmdlet:  PS C:\users\username>$userRoles | DoStuff 

    The pipeline support means that for each item in $userRoles, sent that item to DoStuff.
    The 'begin' and 'end' parts of the function are only called once, while the process part is called for each item in the pipelined list.


    -Eriq VanBibber, CTO, Priasoft Inc.

    Tuesday, July 30, 2019 3:57 PM
  • You don't need a module to pipeline a script. That makes no sense for what is being asked. Again. Guessing is not useful. You msut know PowerShell and basic programming to ask a clear question and to understand how to arrive at an answer. What is being asked is a design question but no fundamental information has been provided.

    The use of the words "USE CASE" has nothing to do with this because no USE CASE has been stated.  So far there have been no technical statements - only a lot of "what ifs".


    \_(ツ)_/

    Tuesday, July 30, 2019 4:02 PM
    Moderator
  • This will help you understand why "USE CASE" is meaningless here: http://tynerblain.com/blog/2007/04/09/sample-use-case-example/


    \_(ツ)_/

    Tuesday, July 30, 2019 4:05 PM
    Moderator
  • Another reason for learning basic PowerShell is that you cannot use semicolons on a command line.  They break the command line.

    You have to define a data method for your script.  You also have to learn if your database calls can work with arrays and strings.  This depends on what database calls your are using.  If SQLServer then SMO can do this with much elss screwing around.


    \_(ツ)_/

    yes i am using sqlserver module to add roles/members. 

    this is my script:

    [CmdletBinding(DefaultParameterSetName='View')]
    Param(
        [Parameter(ParameterSetName='View', Mandatory=$false)]
        [Switch]$View,
    	
    	[Parameter(ParameterSetName='Add', Mandatory=$false)]
        [Switch]$Add,
    	
    	[Parameter(ParameterSetName='Add', Mandatory=$true, Position=1)]
    	[string]$DBName,
    	
    	[Parameter(ParameterSetName='Add', Mandatory=$true, Position=2)]
    	[string]$DBRole,
    	
    	[Parameter(ParameterSetName='Add', Mandatory=$false, Position=3)]
    	[string]$DBMember
    )
    
    Import-Module SqlServer
    
    switch
    {
    	'Add'
    	{
    		$result = "`r{0,-32} | {1,-32}" -f "$server","$DBName"
    		Write-Host $result -NoNewLine	
    			
    		#check if role/member exists
    		$memberExists = $false
    		
    		$Tabular_Analysis_Server = new-Object Microsoft.AnalysisServices.Tabular.Server
    		$Tabular_Analysis_Server.Connect("$server")
    		
    		$TabularDBName = $Tabular_Analysis_Server.Databases[$DBName]
    
    		$TROLE = $TabularDBName.Model.Roles[$DBRole]
    		
    		$RoleMember = New-Object Microsoft.AnalysisServices.Tabular.WindowsModelRoleMember
    		$RoleMember.MemberName = $DBMember
    	
    		if ($TROLE) # if role exists already...check if group exists, or just add group
    		{ 	
    			$memberExists = $TROLE.Members.GetEnumerator() | ?{$_.name -like $DBMember} | select -First 1 | %{$True}
    			
    			if($memberExists)
    			{ 
    				Write-Host "`r`n`r`n Group Member [ $DBMember ] already Exists!`r`n" -foregroundcolor magenta -backgroundcolor black
    			}
    			else
    			{
    				$TROLE.Members.Add($RoleMember)
    				$TabularDBName.Update([Microsoft.AnalysisServices.UpdateOptions]::ExpandFull)
    			}
    			
    			$error.clear()
    			if ($error[0])
    			{	
    				Write-Host ("`r`n`r`nError Adding Member!" + "$($error[0])`r`n") -foregroundcolor magenta -backgroundcolor black
    			}
    		}
    		else	#add role and group
    		{	
    			$AddRole = new-Object Microsoft.AnalysisServices.Tabular.ModelRole
    			$AddRole.Name = $DBRole
    			$RoleMember = New-Object Microsoft.AnalysisServices.Tabular.WindowsModelRoleMember
    			$RoleMember.MemberName = $DBMember
    			$AddRole.Members.Add($RoleMember)
    			$TabularDBName.Model.Roles.Add($AddRole)
    			
    			$error.clear()
    			$TabularDBName.Update([Microsoft.AnalysisServices.UpdateOptions]::ExpandFull)
    			
    			if ($error[0])
    			{	
    				Write-Host "`r`n`r`nError Adding Role/Member to CUBE: $($error[0])`r`n" -foregroundcolor magenta -backgroundcolor black
    			}
    				# UPDATE Role permission
    			
    			$permission=$TabularDBName.Model.Roles["$DBRole"].ModelPermission
    			$permission.value__=[Int]2
    			$TabularDBName.Model.Roles["$DBRole"].ModelPermission=$permission
    			
    			$error.clear()
    			$TabularDBName.Update([Int]1)
    
    			if ($error[0])
    			{
    				Write-Host "`r`nError Updating Role Permission: $($error[0])" -foregroundcolor magenta -backgroundcolor black
    			}
    		}
    			
    		$Tabular_Analysis_Server.Disconnect()
    	}
    	'View'
    	{...}
    }



    • Edited by cataster Tuesday, July 30, 2019 4:27 PM
    Tuesday, July 30, 2019 4:27 PM
  • Looking at your code it is clear that you need to learn PowerShell. It show you do not understand what a "switch" parameter is or how to use it.

    You can also use the "Param" statement I posted to fully simplify your code.  There is no need to pass strings - just pass arrays which is how PowerShell is designed.

    To use switch parameter we only need to do this:

    if($Add){ 
        # code for adding
    }

    if($View){
        # code for viewing
    }
    … etc

    There is no need to use $error.Clear.  YOU should be using Try/Catch.  That is an old habit that VBScript users invented which was also completely unnecessary.

    You must stop and learn PowerShell correctly before you can unwind this mess.  It is a nearly perfect example of how not to write code in any language.

    You are not a trained programmer so you need to learn basic programming.  Get a book anf take these tutorials until it becomes clear to you what you are doing wrong and why.

    Getting Started with Microsoft PowerShell

    To understand how to structure code and use variables correctly this tutorial is helpful:

    PowerShell Style

    These links will help you to understand how to implement the answers and how to write code.


    \_(ツ)_/

    Tuesday, July 30, 2019 4:51 PM
    Moderator
  • PS - you can check a member existence like this:

    if($TROLE.Members[$dbmember]){
         # member exisits
    }else{
         # member not foud
    }

    Learning PowerShell will help you to understand the correct way to use PowerShell with  Net classes.


    \_(ツ)_/

    Tuesday, July 30, 2019 4:53 PM
    Moderator
  • Looking at your code it is clear that you need to learn PowerShell. It show you do not understand what a "switch" parameter is or how to use it.

    You can also use the "Param" statement I posted to fully simplify your code.  There is no need to pass strings - just pass arrays which is how PowerShell is designed.

    To use switch parameter we only need to do this:

    if($Add){ 
        # code for adding
    }

    if($View){
        # code for viewing
    }
    … etc

    There is no need to use $error.Clear.  YOU should be using Try/Catch.  That is an old habit that VBScript users invented which was also completely unnecessary.

    You must stop and learn PowerShell correctly before you can unwind this mess.  It is a nearly perfect example of how not to write code in any language.

    You are not a trained programmer so you need to learn basic programming.  Get a book anf take these tutorials until it becomes clear to you what you are doing wrong and why.

    Getting Started with Microsoft PowerShell

    To understand how to structure code and use variables correctly this tutorial is helpful:

    PowerShell Style

    These links will help you to understand how to implement the answers and how to write code.


    \_(ツ)_/

    But my current code works, and I dont see a reason why switch shouldn't be used..its just a different way of doing things. I know I can use the way you posted with conditional if, but it also works with switch the same way. I just liked using the switch method as I got bored of using ifs every where 😅

    I dont think that indicates a lack of powershell knowledge at all if I choose to do things differently.

    And error.clear() works in my case just fine, yes, I do use try catch a lot recently, but this code at the time i wrote it (last year) works just fine :)

    Tuesday, July 30, 2019 5:07 PM
  • Ok. Do it your way.  One day you may understand what I am trying to get you to see.

    If you could write clean and clear code that was structured correctly then many might be able to help you.  If you choose to invent you own way of programming then you will have to learn how to fix your methods. I don't have the time or patience to go in circles.  The code samples I gave you will solve your issue.  It is up to you to understand them. Of course you could invent a new way to do things.  Its a fools mission but then you want to do it your way.


    \_(ツ)_/

    Tuesday, July 30, 2019 5:49 PM
    Moderator