Issue
I have a csv file, params.csv, consisting of the following dummy data for instance:
"Victor Okwuemu","n939NekyPa8910","VictorO003_gmail.com#EXT#@Hegemongroup.onmicrosoft.com"
"Jackson Kiraly","n939Nek00O1yPa","JacksonK004_gmail.com#EXT#@Hegemongroup.onmicrosoft.com"
"Benson Thomas","n939Nek025yPa","bensonT005_gmail.com#EXT#@Hegemongroup.onmicrosoft.com"
I used a while loop to read each line and extract the strings in each line based on the comma into the variables: displayname
, password
and upn
using these commands: $(echo $line | cut -d "," -f 1)
, $(echo $line | cut -d "," -f 2)
and $(echo $line | cut -d "," -f 3)
respectively as shown below:
file='params.csv'
while read line; do
displayName=$(echo $line | cut -d "," -f 1)
password=$(echo $line | cut -d "," -f 2)
upn=$(echo $line | cut -d "," -f 3)
var1="az ad user create --display-name"
var2="--password"
var3="--user-principal-name"
eval ${var1} ${displayName} ${var2} ${password} ${var3} ${upn}
done < $file
My goal is to pass the extracted strings into an Azure Active Directory CLI commands to create multiple users in Azure Active Directory tenant without using Azure portal.
The program loops, evaluates the first line and adds the user to my Azure active directory tenant, then fails to do for other lines in the the file. However, when I comment out the 'eval' line and echo the variables, the while loop goes through every line and and extracts all the strings for each line.
I have tried writing the commands in various other format as follows:
az ad user create --display-name "$displayName" --password "$password" --user-principal-name "$upn"
echo "az ad user create --display-name $displayName --password $password --user-principal-name $upn"
az ad user create --display-name $(echo $line | cut -d "," -f 1 | tr -d '"') --password $(echo $line | cut -d "," -f 2 | tr -d '"') --user-principal-name $(echo $line | cut -d "," -f 3 | tr -d '"')
All of these methods have failed to create the users as I expected. Any body with an idea on this? The problem here is that the while loop breaks after evaluating the first line in the file.
Solution
As we should avoid using eval
as much as possible due to its vulnerability,
would you please try instead:
#!/bin/bash
file="params.csv"
cmd=("az" "ad" "user" "create" "--display-name")
var2="--password"
var3="--user-principal-name"
while IFS=, read -r displayName password upn; do
"${cmd[@]}" "$displayName" "$var2" "$password" "$var3" "$upn"
done < <(tr -d '"' < "$file")
- You don't need to repead
cut
command to split the lines.read
builtin does it for you by assigningIFS
to the delimiting character. - The command line arguments can be put in an array, not in the single string.
- The surrounding double quotes are removed by the
tr
command, assuming double quotes are not embedded within the strings.
Btw your 1st trial az ad user create --display-name "$displayName" ..
fails
because the variables keeps the surrounding double quotes then the command
line is equivalent to something like
az ad user create --display-name "\"Victor Okwuemu\"" ..
.
As a side note, the echo
command is often used to validate the command line while debugging,
but please keep in mind that echo
sometimes deceives us especially
about the quotings. Even if the output of echo
looks good, it does not
mean the arguments are correctly passed to the command.
An alternative is to write a test command such as:
#!/bin/bash
printf "%s\n" "$@"
which prints the passed arguments line by line.
Try to replace the command az
with ./testcommand
above, run, and examine
the output whether the arguments are properly passed.
[Edit]
As a part of debugging, would you execute a script with the following commands:
az ad user create --display-name "Victor Okwuemu" --password "n939NekyPa8910" --user-principal-name "VictorO003_gmail.com#EXT#@Hegemongroup.onmicrosoft.com"
az ad user create --display-name "Jackson Kiraly" --password "n939Nek00O1yPa" --user-principal-name "JacksonK004_gmail.com#EXT#@Hegemongroup.onmicrosoft.com"
az ad user create --display-name "Benson Thomas" --password "n939Nek025yPa" --user-principal-name "bensonT005_gmail.com#EXT#@Hegemongroup.onmicrosoft.com"
[Edit2]
Would you please try the following for the test purpose:
#!/bin/bash
cmd=("az" "ad" "user" "create" "--display-name")
var2="--password"
var3="--user-principal-name"
while IFS=, read -r displayName password upn; do
"${cmd[@]}" "$displayName" "$var2" "$password" "$var3" "$upn"
done < <(tr -d '"' <<EOS
"Victor Okwuemu","n939NekyPa8910","VictorO003_gmail.com#EXT#@Hegemongroup.onmicrosoft.com"
"Jackson Kiraly","n939Nek00O1yPa","JacksonK004_gmail.com#EXT#@Hegemongroup.onmicrosoft.com"
"Benson Thomas","n939Nek025yPa","bensonT005_gmail.com#EXT#@Hegemongroup.onmicrosoft.com"
EOS
)
[Edit3]
Would you please try the following script to generate another script
newscript.sh
which should be identical to the script in [Edit]
:
#!/bin/bash
file="params.csv"
cmd=("az" "ad" "user" "create" "--display-name")
var2="--password"
var3="--user-principal-name"
{
echo "#!/bin/bash"
echo
while IFS=, read -r displayName password upn; do
echo "${cmd[@]}" "\"$displayName\"" "$var2" "\"$password\"" "$var3" "\"$upn\""
done < <(tr -d '"' < "$file")
} > newscript.sh
Then run the generated script.
[Edit4]
Here is a variant of [Edit3]
without generating a separate script:
#!/bin/bash
file="params.csv"
cmd=("./az" "ad" "user" "create" "--display-name")
var2="--password"
var3="--user-principal-name"
while IFS=, read -r displayName password upn; do
echo "${cmd[@]}" "\"$displayName\"" "$var2" "\"$password\"" "$var3" "\"$upn\""
done < <(tr -d '"' < "$file") | bash -
- The final pipeline
| bash -
feeds the output of previous processings (or generatedaz
command lines) directly tobash
instead of generating a script file. - The double quotes in the command line may be tricky. The outermost double
quotes for each variable are removed by
echo
and the inner ones (escaped with backslashes) are removed when passed to theaz
command. Try to replace the commandaz
with./testcommand
and see the output as I have noted in the first answer.
Answered By - tshiono Answer Checked By - Gilberto Lyons (WPSolving Admin)