Password generator

From Rosetta Code
Task
Password generator
You are encouraged to solve this task according to the task description, using any language you may know.

Create a password generation program which will generate passwords containing random ASCII characters from the following groups:

         lower-case letters:  a ──► z
         upper-case letters:  A ──► Z
                     digits:  0 ──► 9
 other printable characters:  !"#$%&'()*+,-./:;<=>?@[]^_{|}~ 
 (the above character list excludes white-space, backslash and grave) 


The generated password(s) must include   at least one   (of each of the four groups):

   lower-case letter, 
   upper-case letter,
   digit  (numeral),   and 
   one  "other"  character. 


The user must be able to specify the password length and the number of passwords to generate.

The passwords should be displayed or written to a file, one per line.

The randomness should be from a system source or library.

The program should implement a help option or button which should describe the program and options when invoked.

You may also allow the user to specify a seed value, and give the option of excluding visually similar characters.

For example:           Il1     O0     5S     2Z           where the characters are:

  •   capital eye, lowercase ell, the digit one
  •   capital oh, the digit zero
  •   the digit five, capital ess
  •   the digit two, capital zee



6502 Assembly

Unfortunately, easy6502 cannot display text, but it does have a random number generator, so this example merely contains the logic for generating the password itself. The screen can only display colored pixels, and the top 4 bytes are masked off, so this is just a visual aid to show the process in action. The X register is loaded with the password's length (in this case, 20 characters, not counting the null terminator.)

LDY #0
LDX #20
LOOP:
LDA $FE  ;load a random byte
BMI LOOP ;IF GREATER THAN 7F, ROLL AGAIN
CMP #$21 ;ASCII CODE FOR !
BCC LOOP
CMP #$5C 
BEQ LOOP ;NO \
CMP #$60
BEQ LOOP ;NO `
;else, must be a good character
STA $0200,Y
INY
DEX
BNE LOOP
BRK    ;end program
Output:

Code was executed three times and generated the following passwords:

vPX[d5gUY_5lUj[bNDS1
hY+%]lM*j~1Z4YG!0X0<
v}N|4dK(b71qgi-gGwkq

8086 Assembly

This program runs under MS-DOS. The number and length of passwords are given as command line arguments, and there are command line options /E (to exclude Il1 O0 5S 2Z from the passwords), and /S (to set the seed for the RNG, without this option the system time is used). Help is printed when no arguments are given.

	cpu	8086
	bits	16
	;;;	MS-DOS syscalls
gettim:	equ	2Ch	; Get system time
write:	equ	40h	; Write to file
exit:	equ	4Ch	; Exit with return code
	;;;	MS-DOS process data
arg:	equ	80h	; Command line argument (length + string)
	;;;	BIOS calls
conout:	equ	0Eh	; Write character to console
vstate:	equ	0Fh	; Get current video state
section	.text
	org	100h
	mov	ah,gettim	; Seed the RNG using the system time
	int	21h		; (in case of no argument)
	mov	[rnddat],cx
	mov	[rnddat+2],dx
	mov	si,arg		; See if we have any arguments
	lodsb
	test	al,al
	jnz	hasarg
	jmp	usage		; If not, print usage string
	;;;	Parse the command line arguments
hasarg:	xor	bx,bx		; We do, zero-terminate the string
	xchg	al,bl
	mov	[si+bx],al
	mov	di,count	; Place to start reading arguments
doarg:	lodsb			; Get argument byte
.chr:	test	al,al		; Zero?
	jnz 	.arg		; If not, there are arguments left
	jmp	check		; If so, we're done
.arg:	cmp	al,' '		; Space?
	je	doarg		; Then get next character
	cmp	al,'/'		; Option?
	je	opt
	dec	byte [nargs]	; Otherwise, it's an argument
	jnz	rdnum		; Read a number if we still need one
	jmp	usage		; Otherwise, incorrect arguments
rdnum:	xor	bp,bp		; Place to keep number
.chr:	mov	bl,al		; Keep the character in case not a digit
	sub	al,'0'		; Make into digit
	cmp	al,9		; Valid digit?
	ja	.done		; If not, done with number
	add	bp,bp		; Multiply accumulator by 10
	mov	dx,bp
	add	bp,bp
	add 	bp,bp
	add	bp,dx
	xor	ah,ah		; Then add the digit
	add	bp,ax
	lodsb			; Read next digit
	jmp	.chr		
.done:	mov	ax,bp		; Write the number into memory
	stosw
	mov	al,bl		; Restore the character (next argument)
	jmp	doarg.chr
opt:	lodsb			; Get option character
	or	al,32		; Make lowercase
	cmp	al,'e'		; E?
	je	.e
	cmp	al,'s'		; S?
	je	.s
	jmp	usage		; If not, invalid argument
.e:	inc	byte [excl]	; /E: turn on exclusion
	jmp	doarg
.s:	lodsb			; /S: should be followed by '='
	cmp	al,'='
	je	.s_ok
	jmp	usage		; If not, invalid argument
.s_ok:	xor	bp,bp		; DX:BP = RNG state
	xor	dx,dx
.hex:	lodsb			; Get (potential) hex digit
	mov	ah,al		; Keep it around
	call	hexdgt		; Parse hexadecimal digit
	jnc	.hdone		; If invalid, we're done
	shl	bp,1		; Make room for it in the state
	rcl	dx,1		; Because it's a 32-bit value, 
	shl	bp,1		; which is stored in two 16-bit registers,
	rcl	dx,1		; we have to shift and rotate the bits
	shl	bp,1		; one by one.
	rcl	dx,1
	shl	bp,1
	rcl	dx,1
	or	dl,al		; Finally, add in the hexadecimal digit
	jmp	.hex
.hdone:	mov	[rnddat],bp	; Store random seed
	mov	[rnddat+2],dx
	mov	al,ah		; Restore the next character
	jmp	doarg.chr
	;;;	Check the arguments
check:	dec	byte [nargs]	; Were all arguments used?
	jz	.argok
	jmp	usage
.argok:	mov	cx,[count]	; CX = count
	mov	bp,[length]	; BP = length
	test	cx,cx		; Sanity check (count must not be zero)
	mov	si,errmsg.cnt
	jnz	.cntok
	jmp	error
.cntok:	cmp	bp,4		; Length must be at least four 
	mov	si,errmsg.len
	jae	.len2
	jmp	error
.len2:	cmp	bp,255		; Length must be no more than 255
	mov	si,errmsg.lmax
	jbe	mkmask
	jmp	error
	;;;	Make a bitmask in which BP fits (for generating random
	;;;	numbers in the right range)
mkmask:	mov	cx,bp
	mov	bx,cx
.loop:	shr	cx,1
	or	bx,cx
	test	cx,cx
	jnz	.loop
	stc
	rcl 	bx,1
	mov	[lmask],bl	; Password <= 255 chars
	;;;	Generate a password
genpwd:	lea	cx,[bp-4]	; Get length minus four
	mov	di,buffer	; Write password into buffer
	mov	dl,[excl]	; Exclusion flag
	mov	bx,lc		; A lowercase letter,
	mov	ah,lc.len	
	call	rndchr
	mov	bx,uc		; An uppercase letter
	call	rndchr		; (same length of course)
	mov	bx,dgt		; A digit,
	mov	ah,dgt.len
	call	rndchr
	mov	bx,sym		; And a symbol
	mov	ah,sym.len 
	call 	rndchr
	test	cx,cx		; If CX=0, we need no extra characters
	jz	.done
	mov	bx,cr		; Otherwise, we need CX extra characters
	mov	ah,cr.len
.loop:	call	rndchr
	loop	.loop
.done:	mov	ax,0A0Dh	; End with a newline
	stosw
	;;;	Swap the first four characters with random characters
	;;;	from the password, so the four necessary characters won't
	;;;	necessarily be at the beginning.
swap:	mov	dx,bp 		; Get length
	mov	dh,[lmask]	; Load the mask
	mov	si,buffer	; Password buffer
	xor	bh,bh
	xor 	ah,ah		; Starting at zero
.loc:	call	rand		; Get random byte
	and	al,dh		; Mask off unused bits
	cmp	al,dl		; Result within password?
	jae	.loc		; If not, get another random number
	mov	bl,ah		; Load first character in CL
	mov	cl,[si+bx]
	mov	bl,al		; Load random character in CH
	mov	ch,[si+bx]
	mov	[si+bx],cl	; Write them back the other way around
	mov	bl,ah
	mov	[si+bx],ch
	inc	ah		; Next character
	cmp	ah,4		; Are we there yet?
	jb	.loc		; If not, do another character.
	;;;	Write password to standard output
	xor	bx,bx		; File handle 0 = stdout
	lea	cx,[bp+2]	; Length = password length + 2 (for newline)
	mov	dx,si		; Location of password
	mov	ah,write	; Write the password
	int	21h
	jnc	.ok		; Carry clear = success
	mov	si,errmsg.wrt	; Otherwise, print error message
	jmp	error
.ok:	dec	word [count] 	; Need any more passwords?
	jz	stop		; If not, stop
	jmp	genpwd		; Otherwise, make another password
	;;;	Quit with return code 0 (success)
stop:	mov	ax,exit<<8
	int	21h
	;;;	Generate a random character. BX=table, AH=length,
	;;;	DL=exclusion on/off
rndchr:	call	rand		; Random number
	and	al,7Fh		; from 0 to 127
	cmp	al,ah		; Within valid length?
	jae	rndchr		; If not, get new random number
	xlatb			; Otherwise, get character from table
	test	dl,dl		; Is exclusion on?
	jz	.out		; If not, just store it
	push	cx		; Otherwise, keep CX around,
	push	di		; and DI,
	mov	cx,ex.len	; See if character is in exclusion table
	mov	di,ex
	repne	scasb
	pop	di		; restore DI
	pop	cx		; Restore CX
	je	rndchr		; And if it was found, get another character
.out:	stosb			; Store in password buffer
	ret
	;;;	Random number generator using XABC algorithm
	;;;	Returns random byte in AL
rand:	push	cx
	push	dx
	mov	cx,[rnddat]	; CH=X CL=A
	mov	dx,[rnddat+2]	; DH=B DL=C
	inc	ch		; X++
	xor	cl,ch		; A ^= X
	xor	cl,dl		; A ^= C
	add	dh,cl		; B += A
	mov	al,dh		; C' = B 
	shr	al,1		; C' >>= 1
	xor	al,cl		; C' ^= A
	add	al,dl		; C' += C
	mov	dl,al		; C = C'
	mov	[rnddat],cx
	mov	[rnddat+2],dx
	pop	dx
	pop	cx
	ret
	;;;	If AL is a hexadecimal digit in ASCII, set AL to be its 
	;;;	value. Carry flag set if digit was valid.
hexdgt:	or	al,32		; Make letter lowercase (numbers unchanged)
	sub	al,'0'		; Subtract 0
	cmp	al,10		; If it is a valid digit now, we're done
	jc	.out
	sub	al,39		; Otherwise, correct for 
	cmp	al,17	
.out:	ret
	;;;	Write the help message, and stop with return code 2
usage:	mov	si,help
	;;;	Write an error message, directly to the console, bypassing
	;;;	DOS to ensure it does not end up in the redirected output.
	;;;	Then, stop with return code 2 (failure)
error:	mov	ah,vstate	; Retrieve current video state
	int	10h		; (this sets BH = current page)
.loop	lodsb			; Get string byte
	test	al,al		; Zero?
	jz	.out		; Then we have reached the end
	mov	ah,conout	; Otherwise, write the character
	int	10h
	jmp	.loop		; And get another one
.out:	mov	ax,exit<<8|2	; Stop with error code 2
	int	21h 
section	.data
nargs:	db	3		; We need two non-option arguments
excl:	db	0		; Exclusion is off by default
cr:	;;;	Password characters
lc:	db	'abcdefghijklmnopqrstuvwxyz'
.len:	equ	$-lc
uc:	db	'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
.len:	equ	$-uc
dgt:	db	'0123456789'
.len:	equ	$-dgt
sym:	db	'!"#$%&()*+,-./:;<=>?@[]^_{|}~',39 ; 39=single quote
.len:	equ 	$-sym
cr.len:	equ	$-cr
ex:	db	'Il1O05S2Z'	; Excluded characters
.len:	equ	$-ex
	;;;	Help message
help:	db	'PASSGEN [/S=seed] [/E] count length',13,10
	db	9,'generate <count> passwords of length <length>',13,10
	db	13,10
	db	9,'/S=seed: set RNG seed (hexadecimal number)',13,10
	db	9,'/E:      exclude visually similar characters',13,10
	db	0
errmsg:	;;;	Error messages
.len:	db	'Minimum password length is 4.',0
.lmax:	db	'Maximum password length is 255.',0
.cnt:	db	'At least one password must be generated.',0
.wrt:	db	'Write error.',0
section	.bss
count:	resw	1		; Amount of passwords to generate
length:	resw	1		; Length of passwords
lmask:	resb	1		; Mask for random number generation
rnddat:	resb	4		; RNG state
buffer:	resb	257		; Space to store password

Action!

BYTE FUNC GetNumParam(CHAR ARRAY text BYTE min,max)
  BYTE res

  DO
    PrintF("Input %S (%B-%B): ",text,min,max)
    res=InputB()
  UNTIL res>=min AND res<=max
  OD
RETURN (res)

BYTE FUNC GetBoolParam(CHAR ARRAY text)
  CHAR ARRAY s(255)

  DO
    PrintF("%S? (Y/N): ",text)
    InputS(s)
    IF s(0)=1 THEN
      IF s(1)='y OR s(1)='Y THEN
        RETURN (1)
      ELSEIF s(1)='n OR s(1)='N THEN
        RETURN (0)
      FI
    FI
  OD
RETURN (0)

PROC Shuffle(CHAR ARRAY s)
  BYTE i,j
  CHAR tmp

  i=s(0)
  WHILE i>1
  DO
    j=Rand(i)+1
    tmp=s(i) s(i)=s(j) s(j)=tmp
    i==-1
  OD
RETURN

BYTE FUNC Contains(CHAR ARRAY s CHAR c)
  BYTE i

  IF s(0)=0 THEN
    RETURN (0)
  FI
  FOR i=1 TO s(0)
  DO
    IF s(i)=c THEN
      RETURN (1)
    FI
  OD
RETURN (0)

CHAR FUNC RandChar(CHAR ARRAY s,unsafe)
  BYTE len
  CHAR c

  len=s(0)
  DO
    c=s(Rand(len)+1)
  UNTIL Contains(unsafe,c)=0
  OD
RETURN (c)

PROC Generate(CHAR ARRAY res BYTE len,safe)
  DEFINE PTR="CARD"
  CHAR ARRAY st,
    upper="ABCDEFGHIJKLMNOPQRSTUVWXYZ",
    lower="abcdefghijklmnopqrstuvwxyz",
    numbers="0123456789",
    special="!""#$%&'()*+,-./:;<=>?@[]^_|",
    unsafe="Il1O05S2Z"
  PTR ARRAY sets(4)
  BYTE i

  sets(0)=upper   sets(1)=lower
  sets(2)=numbers sets(3)=special

  res(0)=len
  FOR i=1 TO len
  DO
    IF safe THEN
      res(i)=RandChar(sets(i MOD 4),unsafe)
    ELSE
      res(i)=RandChar(sets(i MOD 4),"")
    FI
  OD
  Shuffle(res)
RETURN

PROC PrintHelp()
  PutE()
  PrintE("Program generates random passwords")
  PrintE("containing at least one upper-case")
  PrintE("letter, one lower-case letter, one")
  PrintE("digit and one special character.")
  PrintE("It is possible to exclude visually")
  PrintE("similar characters Il1O05S2Z.")
  PutE()
RETURN

PROC Main()
  BYTE len,count,safe,i,again,help
  CHAR ARRAY password(255)

  help=GetBoolParam("Show help")
  IF help THEN
    PrintHelp()
  FI

  DO
    len=GetNumParam("length of password",4,30)
    safe=GetBoolParam("Exclude similar chars")
    count=GetNumParam("number of passwords",1,10)
    PutE()
    FOR i=1 TO count
    DO
      Generate(password,len,safe)
      PrintF("%B. %S%E",i,password)
    OD
    PutE()
    again=GetBoolParam("Generate again")
  UNTIL again=0
  OD
RETURN
Output:

Screenshot from Atari 8-bit computer

Show help? (Y/N): Y

Program generates random passwords
containing at least one upper-case
letter, one lower-case letter, one
digit and one special character.
It is possible to exclude visually
similar characters Il1O05S2Z.

Input length of password (4-30): 25
Exclude similar chars? (Y/N): Y
Input number of passwords (1-10): 6

1. 'Eo4qRf3379LF;-D&|s8bdaC+
2. L'3nw+N94J9tw*Bx=vR9+6L.p
3. @7uAAjj3"Vi@r$E767'iE;Fm3
4. 3y)^4Lb9f8^oVT_]nVK33n>Nr
5. vi4>Xv46G(eK<P6dCq;#zU6-9
6. ^-/MwtrpvzW7;K36Y7jJ_8X8*

Generate again? (Y/N): N

Ada

with Ada.Numerics.Discrete_Random;
with Ada.Strings.Fixed;
with Ada.Command_Line;
with Ada.Integer_Text_IO;
with Ada.Text_IO;

procedure Mkpw is

   procedure Put_Usage;
   procedure Parse_Command_Line (Success : out Boolean);
   function Create_Password (Length : in Positive;
                             Safe   : in Boolean)
                            return String;

   procedure Put_Usage is
      use Ada.Text_IO;
   begin
      Put_Line ("Usage:                                                     ");
      Put_Line ("   mkpw help   - Show this help text                       ");
      Put_Line ("   mkpw [count <n>] [length <l>] [seed <s>] [safe]         ");
      Put_Line ("     count <n>  - Number of passwords generated (default 4)");
      Put_Line ("     length <l> - Password length (min 4)       (default 4)");
      Put_Line ("     seed <l>   - Seed for random generator     (default 0)");
      Put_Line ("     safe       - Do not use unsafe characters  (0O1lIS52Z)");
   end Put_Usage;

   Lower_Set  : constant String := "abcdefghijklmnopqrstuvwxyz";
   Upper_Set  : constant String := "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   Digit_Set  : constant String := "0123456789";
   Spec_Set   : constant String := "!""#$%&'()*+,-./:;<=>?@[]^_{|}~";
   Unsafe_Set : constant String := "0O1lI5S2Z";

   Full_Set : constant String := Lower_Set & Upper_Set & Digit_Set & Spec_Set;
   subtype Full_Indices is Positive range Full_Set'Range;

   package Full_Index_Generator is
      new Ada.Numerics.Discrete_Random (Full_Indices);

   Index_Generator : Full_Index_Generator.Generator;

   Config_Safe          : Boolean  := False;
   Config_Count         : Natural  := 4;
   Config_Length        : Positive := 6;
   Config_Seed          : Integer  := 0;
   Config_Show_Help     : Boolean  := False;

   procedure Parse_Command_Line (Success : out Boolean) is
      use Ada.Command_Line;
      Got_Safe,   Got_Count : Boolean  := False;
      Got_Length, Got_Seed  : Boolean  := False;
      Last       : Positive;
      Index      : Positive := 1;
   begin
      Success := False;
      if Argument_Count = 1 and then Argument (1) = "help" then
         Config_Show_Help := True;
         return;
      end if;

      while Index <= Argument_Count loop
         if Ada.Command_Line.Argument (Index) = "safe" then
            if Got_Safe then
               return;
            end if;
            Got_Safe := True;
            Config_Safe     := True;
            Index := Index + 1;
         elsif Argument (Index) = "count" then
            if Got_Count then
               return;
            end if;
            Got_Count := True;
            Ada.Integer_Text_IO.Get (Item => Config_Count,
                                     From => Argument (Index + 1),
                                     Last => Last);
            if Last /= Argument (Index + 1)'Last then
               return;
            end if;
            Index := Index + 2;
         elsif Argument (Index) = "length" then
            if Got_Length then
               return;
            end if;
            Got_Length := True;
            Ada.Integer_Text_IO.Get (Item => Config_Length,
                                     From => Argument (Index + 1),
                                     Last => Last);
            if Last /= Argument (Index + 1)'Last then
               return;
            end if;
            if Config_Length < 4 then
               return;
            end if;
            Index := Index + 2;
         elsif Argument (Index) = "seed" then
            if Got_Seed then
               return;
            end if;
            Got_Seed := True;
            Ada.Integer_Text_IO.Get (Item => Config_Seed,
                                     From => Argument (Index + 1),
                                     Last => Last);
            if Last /= Argument (Index + 1)'Last then
               return;
            end if;
            Index := Index + 2;
         else
            return;
         end if;
      end loop;
      Success := True;
   exception
      when Constraint_Error | Ada.Text_IO.Data_Error =>
         null;
   end Parse_Command_Line;

   function Create_Password (Length : in Positive;
                             Safe   : in Boolean)
                            return String
   is

      function Get_Random (Safe : in Boolean)
                          return Character;

      function Get_Random (Safe : in Boolean)
                          return Character
      is
         use Ada.Strings.Fixed;
         C : Character;
      begin
         loop
            C := Full_Set (Full_Index_Generator.Random (Index_Generator));
            if Safe then
               exit when Index (Source => Unsafe_Set, Pattern => "" & C) = 0;
            else
               exit;
            end if;
         end loop;
         return C;
      end Get_Random;

      function Has_Four (Item : in String)
                        return Boolean;

      function Has_Four (Item : in String)
                        return Boolean
      is
         use Ada.Strings.Fixed;
         Has_Upper, Has_Lower : Boolean := False;
         Has_Digit, Has_Spec  : Boolean := False;
      begin
         for C of Item loop
            if Index (Upper_Set, "" & C) /= 0 then Has_Upper := True; end if;
            if Index (Lower_Set, "" & C) /= 0 then Has_Lower := True; end if;
            if Index (Digit_Set, "" & C) /= 0 then Has_Digit := True; end if;
            if Index (Spec_Set,  "" & C) /= 0 then Has_Spec  := True; end if;
         end loop;
         return Has_Upper and Has_Lower and Has_Digit and Has_Spec;
      end Has_Four;

      Password : String (1 .. Length);
   begin
      loop
         for I in Password'Range loop
            Password (I) := Get_Random (Safe);
         end loop;
         exit when Has_Four (Password);
      end loop;
      return Password;
   end Create_Password;

   Parse_Success : Boolean;
begin

   Parse_Command_Line (Parse_Success);

   if Config_Show_Help or not Parse_Success then
      Put_Usage;  return;
   end if;

   if Config_Seed = 0 then
      Full_Index_Generator.Reset (Index_Generator);
   else
      Full_Index_Generator.Reset (Index_Generator, Config_Seed);
   end if;

   for Count in 1 .. Config_Count loop
      Ada.Text_IO.Put_Line (Create_Password (Length => Config_Length,
                                             Safe   => Config_Safe));
   end loop;

end Mkpw;
Output:
$ ./mkpw count 8 length 22 safe
">M<P]GMHf77cbT%b8.eX]
W3Q&k~L*R,z)39(a{AvGon
3Xvh=:P9BGGU$=YPD{dFW@
^X)]vV4fFtCXksgv+,usHx
$89*bxyb?@aQEQ8~~vaq9o
FW{F*-]tDJH~]/7CLtRe-k
6%K6(8&fyX=,&TBFvW%kz3
+@pyJ'3YQ'%~9?Tm/BHk?A

Applesoft BASIC

1 N=1
2 L=8
3 M$=CHR$(13)
4 D$=CHR$(4)
5 S$(0)="S"
6 F$="A FILE"
7 C$(1)=" (CURRENT OPTION)"
8 DEF FN R(T)=ASC(MID$(G$(T),INT(RND(1)*LEN(G$(T))+1),1))
9 GOSUB 750
10 FOR Q = 0 TO 1 STEP 0
20     GOSUB 50CHOOSE
30 NEXT Q
40 END

REM *** CHOOSE ***
50 PRINT M$M$"1 GEN 2 DISP 3 FILE 4 LEN 5 NUM 6 SEED"
60 PRINT "7 CHR 8 HELP 9 QUIT "CHR$(10)"CHOOSE AN OPTION: ";
70 GET K$
75 IF K$ > CHR$(95) THEN K$ = CHR$(ASC(K$) - 32)
80 PRINT K$
85 ON VAL(K$) GOTO 100,200,300,400,500,600,700,800,900
90 GOTO 210OPTIONS

REM *** GENERATE ***
100 PRINT M$ 
105 IF L > 32 THEN PRINT "UM... OK, THIS MIGHT TAKE A BIT."M$
110 GOSUB 340OPEN
115 FOR P=1 TO N
120     P$=""
125     FOR I=1 TO L
135         P$=P$+CHR$(FNR(I*(I<5)))
140     NEXT I
REM     SHUFFLE FIRST 4
150     FOR I = 1 TO 4
151         C$=MID$(P$,I,1)
152         J=INT(RND(1)*L)+1
153         H$=MID$(P$,J,1)
154         P$=MID$(P$,1,J-1)+C$+MID$(P$,J+1,L)
155         P$=MID$(P$,1,I-1)+H$+MID$(P$,I+1,L)
156     NEXT I
180     PRINT P$
185 NEXT P
190 GOTO 380CLOSE

REM *** DISPLAY ***
200 C = 0
REM *** OPTIONS ***
210 HOME
215 PRINT "PASSWORD GENERATOR"M$M$
220 PRINT "1.  GENERATE "N" PASSWORD"S$(N=1)M$
225 PRINT "2.  DISPLAYED"C$(C=0)M$"       OR"
230 PRINT "3.  WRITTEN TO "F$C$(C=1)M$
235 PRINT "4.  SPECIFY THE PASSWORD LENGTH = "L;M$
240 PRINT "5.  SPECIFY THE NUMBER OF PASSWORDS TO"M$TAB(31)"GENERATE"
245 PRINT "6.  SPECIFY A SEED VALUE"M$
250 PRINT "7.  EXCLUDE VISUALLY SIMILAR CHARACTERS"M$
255 PRINT "8.  HELP AND OPTIONS"
260 RETURN

REM *** WRITE TO A FILE ***
300 C = 1
310 GOTO 210OPTIONS
REM *** OPEN A FILE ***
340 IF NOT C THEN RETURN
345 PRINT D$"OPEN "F$"
350 PRINT D$"CLOSE"F$
355 PRINT D$"DELETE "F$
360 PRINT D$"OPEN "F$
365 PRINT D$"WRITE "F$
370 RETURN
REM *** CLOSE A FILE ***
380 IF NOT C THEN RETURN
385 PRINT D$"CLOSE"F$
390 RETURN

REM *** SET PASSWORD LENGTH ***
400 PRINT M$
410 FOR I = 0 TO 1 STEP 0
420 INPUT "ENTER A NUMBER FROM 4 TO 255 TO SPECIFY THE PASSWORD LENGTH = ";L
430 IF L >= 4 AND L < 256 THEN RETURN
440 PRINT "?OUT OF RANGE"
450 NEXT I

REM *** SET NUMBER OF PASSWORDS TO GENERATE ***
500 PRINT M$
510 FOR I = 0 TO 1 STEP 0
520 INPUT "ENTER A NUMBER FROM 1 AND UP TO SPECIFY THE NUMBER OF PASSWORDS TO GENERATE: ";N
530 IF N >= 1 THEN RETURN
540 PRINT "?OUT OF RANGE."
550 NEXT I

REM *** SET A SEED VALUE ***
600 PRINT M$
610 INPUT "ENTER A SEED VALUE: ";S%
620 PRINT RND(S%)
630 RETURN

REM *** EXCLUDE ***
700 PRINT M$
705 INPUT "ENTER CHARACTERS TO EXCLUDE:";E$
REM *** GROUPS ***
REM ALWAYS EXCLUDE BACKSLASH AND BACKTICK (GRAVE)
710 E$=CHR$(92)+CHR$(96)+E$
711 FOR G = 1 TO 4
712     G$(G) = ""
713 NEXT G
720 FOR G = 1 TO 2
721     FOR K = ASC("A") + (G - 1) * 32 TO ASC("Z") + (G - 1) * 32
722         GOSUB 770ADD
723 NEXT K, G
730 FOR K = 33 TO 64
731     G = 3 + (K < ASC(STR$(0)) OR K > ASC(STR$(9)))
732     GOSUB 770ADD
733 NEXT K
734 FOR K = 91 TO 96
735     GOSUB 770ADD
736 NEXT K
737 FOR K = 123 TO 126
738     GOSUB 770ADD
739 NEXT K
740 G$(0) = ""
741 FOR G = 1 TO 4
742     IF LEN(G$(G)) THEN G$(0) = G$(0) + G$(G) : NEXT G : GOTO 800HELP
743 ?"THERE MUST BE AT LEAST ONE CHARUNRACTER IN EACH GROUP"
744 GOTO 705
REM *** DEFAULT (QUICK) ***
750 G$(1)="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
751 FOR I=97TO122:G$(2)=G$(2)+CHR$(I):NEXT
753 G$(3)="0123456789"
754 G$(4)="!"+CHR$(34)+"#$%&'()*+,-./:;<=>?@"+CHR$(91)+"]^"+CHR$(95)
755 FOR I=123TO126:G$(4)=G$(4)+CHR$(I):NEXTI
756 G$(0)=G$(0)+G$(1)+G$(2)+G$(3)
757 GOTO 210OPTIONS
REM *** ADD TO GROUP
770 C$ = CHR$(K)
775 FOR E = 1 TO LEN(E$)       
780         IF C$ <> MID$(E$,E,1) THEN NEXT E : G$(G)=G$(G)+C$ : ?C$;
790 RETURN

REM *** HELP ***
800 HOME
805 PRINT "GENERATE PASSWORDS CONTAINING RANDOM"
810 PRINT "ASCII CHARACTERS FROM THESE GROUPS:"M$
815 PRINT "  LOWERCASE UPPERCASE DIGIT OTHER"M$
820 PRINT "  "LEFT$(G$(2),9)TAB(13)LEFT$(G$(1),9)TAB(23)LEFT$(G$(3),5)TAB(29)LEFT$(G$(4),11)
825 PRINT "  "MID$(G$(2),10,9)TAB(13)MID$(G$(1),10,9)TAB(23)MID$(G$(3),6,5)TAB(29)MID$(G$(4),12,11)
826 PRINT "  "MID$(G$(2),19,9)TAB(13)MID$(G$(1),19,9)TAB(29)MID$(G$(4),23,15)M$
840 PRINT "YOU MAY CHOOSE THE PASSWORD LENGTH, AND"
845 PRINT "HOW MANY PASSWORDS TO GENERATE. IT IS"
850 PRINT "ENSURED THAT THERE IS AT LEAST ONE"
855 PRINT "CHARACTER FROM EACH OF THE GROUPS IN"
860 PRINT "EACH PASSWORD. THERE IS AN OPTION TO"
865 PRINT "EXCLUDE VISUALLY SIMILAR CHARACTERS."
870 RETURN

REM *** QUIT ***
900 Q = 1
910 VTAB 23
920 RETURN

Arturo

lowercase: `a`..`z`
uppercase: `A`..`Z`
digits: `0`..`9`
other: map split "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~" => [to :char]

any: lowercase ++ uppercase ++ digits ++ other

generate: function [length][
    if length < 4 [
        print (color #red "ERROR: ") ++ "password length too short"
        exit
    ]

    chars: new @[sample lowercase sample uppercase sample digits sample other]
    while [length > size chars][
        'chars ++ sample any
    ]

    join shuffle chars
]

if 0 = size arg [
    print {
        ---------------------------------
        Arturo password generator
        (c) 2021 drkameleon
        ---------------------------------
        usage: passgen.art <length>
    }
    exit
]

loop 1..10 'x [
    print generate to :integer first arg
]
Output:
; executed with ./passgen.art 10

T{6G7:qgyp
s7|iC2S0Tf
D6.Ac}1}oz
9**;81R@h<
H+|0CBN(ca
x!C#0yri]@
OfV7wlg*<G
{0z3MVJUNg
yULk,=B)84
C>o6]&9y<X

AWK

# syntax: GAWK -f PASSWORD_GENERATOR.AWK [-v mask=x] [-v xt=x]
#
# examples:
#   REM 4 character passwords using Rosetta Code default of: lower, upper, number, other
#   GAWK -f PASSWORD_GENERATOR.AWK
#
#   REM 8 character passwords; Rosetta Code default plus another four
#   GAWK -f PASSWORD_GENERATOR.AWK -v mask=LUNPEEEE
#
#   REM 8 character passwords ignoring Rosetta Code requirement
#   GAWK -f PASSWORD_GENERATOR.AWK -v mask=EEEEEEEE
#
#   REM help
#   GAWK -f PASSWORD_GENERATOR.AWK ?
#
# sorting:
#   PROCINFO["sorted_in"] is used by GAWK
#   SORTTYPE is used by Thompson Automation's TAWK
#
BEGIN {
    PROCINFO["sorted_in"] = "@ind_str_asc" ; SORTTYPE = 1
    srand()
# setup strings of valid characters used by mask
    arr["L"] = "abcdefghijklmnopqrstuvwxyz"        # Lower case
    arr["U"] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"        # Upper case
    arr["N"] = "0123456789"                        # Numbers
    arr["P"] = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~"   # Punctuation: I.E. other
    arr["A"] = arr["L"] arr["U"]                   # Alphabetic: lower and upper case
    arr["E"] = arr["L"] arr["U"] arr["N"] arr["P"] # Everything: lower, upper, number, punctuation
    arr["B"] = " "                                 # Blank: a space
# validate array index and length of assignment
    for (i in arr) {
      if (length(i) != 1) {
        error(sprintf("arr[%s], index is invalid",i))
      }
      if (length(arr[i]) == 0) {
        error(sprintf("arr[%s], is null",i))
      }
      mask_valids = sprintf("%s%s",mask_valids,i)
    }
# validate command line variables
    if (mask == "") {
      mask = "LUNP" # satisfy Rosetta Code task requirement
    }
    if (xt == "") {
      xt = 10 # default iterations
    }
    if (xt !~ /^[0-9]+$/) {
      error("xt is not 0-9")
    }
# validate each character in mask
    for (i=1; i<=length(mask); i++) {
      c = substr(mask,i,1)
      if (!(c in arr)) {
        error(sprintf("mask position %d is %s, invalid",i,c))
      }
    }
# help
    if (ARGV[1] == "?") {
      syntax()
      exit(0)
    }
    if (ARGC-1 != 0) {
      error("no files allowed on command line")
    }
# make passwords
    if (errors == 0) {
      for (i=1; i<=xt; i++) {
        make_password()
      }
    }
    exit(errors+0)
}
function error(message) {
    printf("error: %s\n",message)
    errors++
}
function make_password(  c,i,indx,password,valids) {
    for (i=1; i<=length(mask); i++) {  # for each character in mask
      c = substr(mask,i,1)             # extract 1 character from mask
      valids = arr[c]                  # valid characters for this position in mask
      indx = int(rand() * length(valids)) + 1
      c = substr(valids,indx,1)        # extract 1 character from list of valids
      password = password c            # build password
    }
    printf("%s\n",password)
}
function syntax(  cmd,i) {
    cmd = "GAWK -f PASSWORD_GENERATOR.AWK"
    printf("syntax: %s [-v mask=x] [-v xt=x]\n\n",cmd)
    printf("  mask  1..n bytes determines password format and length; consists of %s\n",mask_valids)
    for (i in arr) {
      printf("%9s - %s\n",i,(arr[i] == " ") ? "<space>" : arr[i])
    }
    printf("  xt    number of passwords to generate\n\n")
    printf("example: %s -v mask=%s -v xt=%s\n",cmd,mask,xt)
}
Output:
GAWK -f PASSWORD_GENERATOR.AWK -v mask=LUNPEEEE -v xt=5
iX1<-a%p
xH6]rrZ+
eK8*5@P/
cY9'kwG*
qS9=7wtU

C

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define DEFAULT_LENGTH 4
#define DEFAULT_COUNT 1

char* symbols[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz", "0123456789", "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~"};
int length = DEFAULT_LENGTH;
int count = DEFAULT_COUNT;
unsigned seed;
char exSymbols = 0;

void GetPassword () {
    //create an array of values that determine the number of characters from each category 
    int lengths[4] = {1, 1, 1, 1};
    int count = 4;
    while (count < length) {
        lengths[rand()%4]++;
        count++;
    } 

    //loop through the array of lengths and set the characters in password
    char password[length + 1];
    for (int i = 0; i < length; ) { 
        //pick which string to read from
        int str = rand()%4;
        if (!lengths[str])continue;   //if the number of characters for that string have been reached, continue to the next interation

        char c;
        switch (str) {
            case 2:
                c = symbols[str][rand()%10];
                while (exSymbols && (c == 'I' || c == 'l' || c == '1' || c == 'O' || c == '0' || c == '5' || c == 'S' || c == '2' || c == 'Z'))
                    c = symbols[str][rand()%10];
                password[i] = c;
            break;

            case 3:
                c = symbols[str][rand()%30];
                while (exSymbols && (c == 'I' || c == 'l' || c == '1' || c == 'O' || c == '0' || c == '5' || c == 'S' || c == '2' || c == 'Z'))
                    c = symbols[str][rand()%30];
                password[i] = c;
            break;

            default:
                c = symbols[str][rand()%26];
                while (exSymbols && (c == 'I' || c == 'l' || c == '1' || c == 'O' || c == '0' || c == '5' || c == 'S' || c == '2' || c == 'Z'))  
                    c = symbols[str][rand()%26];
                password[i] = c;
            break;
        }

        i++;
        lengths[str]--;
    }

    password [length] = '\0';
    printf ("%s\n", password);
}

int main (int argc, char* argv[]) {
    seed = (unsigned)time(NULL);

    //handle user input from the command line
    for (int i = 1; i < argc; i++) {
        switch (argv[i][1]) {
            case 'l':
                if (sscanf (argv[i+1], "%d", &length) != 1) {
                    puts ("Unrecognized input. Syntax: -l [integer]");
                    return -1;
                }
                
                if (length < 4) {
                    puts ("Password length must be at least 4 characters.");
                    return -1;
                }
                i++;                
            break;

            case 'c':
                if (sscanf (argv[i+1], "%d", &count) != 1) {
                    puts ("Unrecognized input. Syntax: -c [integer]");
                    return -1;
                }

                if (count <= 0) {
                    puts ("Count must be at least 1.");
                    return -1;
                }
                i++;
            break;

            case 's':
                if (sscanf (argv[i+1], "%d", &seed) != 1) {
                    puts ("Unrecognized input. Syntax: -s [integer]");
                    return -1;
                }
                i++;
            break;

            case 'e':
                exSymbols = 1;
            break;

            default:
                help:
                printf ("Help:\nThis program generates a random password.\n"
                "Commands:"
                   "Set password length: -l [integer]\n"
                   "Set password count: -c [integer]\n"
                   "Set seed: -s [integer]\n"
                   "Exclude similiar characters: -e\n"
                   "Display help: -h");
                return 0;
            break;
        }    
    }

    srand (seed);

    for (int i = 0; i < count; i++)
        GetPassword();
    
    return 0;
}
Output:
./password
5zK@

./password -c 3 -l 10
L=C17QQn<$
uyC;X5kc76
D8Yw.827$]

C#

using System;
using System.Linq;

class Program
{
    const string Lower = "abcdefghijklmnopqrstuvwxyz";
    const string Upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    const string Digits = "0123456789";
    const string Symbols = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~";
    static readonly string[] Full = {Lower, Upper, Digits, Symbols, Lower + Upper + Digits + Symbols};

    const string Similar = "Il1O05S2Z";
    static readonly string[] Excluded = Full.Select(x => new string(x.Except(Similar).ToArray())).ToArray();

    static Random _rng = new Random();
    static string[] _symbolSet = Full;

    static void Main(string[] args)
    {
        int length = 12, count = 1;
        try
        {
            foreach (var x in args.Select(arg => arg.Split(':')))
            {
                switch (x[0])
                {
                    case "-l": length = int.Parse(x[1]); break;
                    case "-c": count = int.Parse(x[1]); break;
                    case "-s": _rng = new Random(x[1].GetHashCode()); break;
                    case "-x": _symbolSet = bool.Parse(x[1]) ? Excluded : Full; break;
                    default: throw new FormatException("Could not parse arguments");
                }
            }
        }
        catch { ShowUsage(); return; }
        try
        {
            for (int i = 0; i < count; i++)
                Console.WriteLine(GeneratePass(length));
        }
        catch (Exception ex) { Console.WriteLine("Error: " + ex.Message); }
    }

    static void ShowUsage()
    {
        Console.WriteLine("Usage: PASSGEN [-l:length] [-c:count] [-s:seed] [-x:(true|false)]");
        Console.WriteLine("\t-l: the length of the generated passwords");
        Console.WriteLine("\t-c: the number of passwords to generate");
        Console.WriteLine("\t-s: seed for the random number generator");
        Console.WriteLine("\t-x: exclude similar characters: " + Similar);
        Console.WriteLine("Example: PASSGEN -l:10 -c:5 -s:\"Sample Seed\" -x:true");
    }

    static string GeneratePass(int length)
    {
        var minLength = _symbolSet.Length - 1;
        if(length < minLength)
            throw new Exception("password length must be " + minLength + " or greater");

        int[] usesRemaining = Enumerable.Repeat(1, _symbolSet.Length).ToArray();
        usesRemaining[minLength] = length - minLength;
        var password = new char[length];
        for (int ii = 0; ii < length; ii++)
        {
            int set = _rng.Next(0, _symbolSet.Length);
            if (usesRemaining[set] > 0)
            {
                usesRemaining[set]--;
                password[ii] = _symbolSet[set][_rng.Next(0, _symbolSet[set].Length)];
            }
            else ii--;
        }
        return new string(password);
    }
}
Output:
PASSGEN -l:12 -c:6
Bc'9(i(&bw]G
g=9JnTy2tzMn
G8^UtYdx4D9Y
^S4uq?*yXEA=
W{3*hdk&0p?R
"4Ips4;8S3o~

C++

#include <iostream>
#include <string>
#include <algorithm>
#include <ctime>

const std::string CHR[] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz", 
                            "0123456789", "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~" };
const std::string UNS = "O0l1I5S2Z";

std::string createPW( int len, bool safe ) {
    std::string pw;
    char t;
    for( int x = 0; x < len; x += 4 ) {
        for( int y = x; y < x + 4 && y < len; y++ ) {
            do {
                t = CHR[y % 4].at( rand() % CHR[y % 4].size() );
            } while( safe && UNS.find( t ) != UNS.npos );
            pw.append( 1, t );
        }
    }
    std::random_shuffle( pw.begin(), pw.end() );
    return pw;
}
void generate( int len, int count, bool safe ) {
    for( int c = 0; c < count; c++ ) {
        std::cout << createPW( len, safe ) << "\n";
    }
    std::cout << "\n\n";
}
int main( int argc, char* argv[] ){
    if( argv[1][1] == '?' || argc < 5 ) {
        std::cout << "Syntax: PWGEN length count safe seed /?\n"
                     "length:\tthe length of the password(min 4)\n"
                     "count:\thow many passwords should be generated\n"
                     "safe:\t1 will exclude visually similar characters, 0 won't\n"
                     "seed:\tnumber to seed the random generator or 0\n"
                     "/?\tthis text\n\n";
    } else {
        int l = atoi( argv[1] ),
            c = atoi( argv[2] ),
            e = atoi( argv[3] ), 
            s = atoi( argv[4] );
        if( l < 4 ) {
            std::cout << "Passwords must be at least 4 characters long.\n\n";
        } else {
            if (s == 0) {
               std::srand( time( NULL ) );
            } else {
               std::srand( unsigned( s ) );
            }
            generate( l, c, e != 0 );
        }
    }
    return 0;   
}
Output:
PWGEN 6 6 1 8
9@NcCe
4jERh!
<zX4Mr
Cob+X7
GU8_jt
rF9t%F

PWGEN 6 6 0 8
cn2ZO~
W:iRm7
0|hyJU
.h3JfL
3oq;FT
u*VT4t

Ceylon

module.ceylon:

module rosetta.passwordgenerator "1.0.0" {
    import ceylon.random "1.2.2";
}

run.ceylon:

import ceylon.random {
    DefaultRandom,
    Random
}

Character[] lowerCaseChars = 'a'..'z';
Character[] upperCaseChars = 'A'..'Z';
Character[] numsAsChars = '0'..'9';
Character[] specialChars = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~".sequence();
Character[] allChars = lowerCaseChars.append(upperCaseChars)
                                     .append(numsAsChars)
                                     .append(specialChars);

shared void run() {
    print("2 passwords of size 8");
    print("------");
    generatePasswords(8,2).each(print);
    print("------");
    print("5 passwords of size 12");
    print("------");
    generatePasswords(12,5).each(print);
    print("------");
    print("7 passwords of size 16");
    print("------");
    generatePasswords(16,7).each(print);
    print("------");
    print("2 passwords of size 16 exclude AiX24!~");
    print("------");
    generatePasswords(16,7,"AiX24!~".sequence()).each(print);
}

String[] generatePasswords(Integer numChars, Integer numPasswords, Character[] excludedChars=[])
    => [for (count in 1..numPasswords) generatePassword(numChars,excludedChars) ];

//The generated password(s) must include at least one lower-case letter, one upper-case letter and one character from digits and 'other'.
String generatePassword(Integer numChars, Character[] excludedChars) {
    "Must provide a password length of at least 4"
    assert(numChars >= 4);

    value random = DefaultRandom();

    value fixedPartOfPassword = passwordFragmentForRequirements(random,excludedChars);

    value randomPart =
       randomPartOfPassword{ random = random;
                             index = fixedPartOfPassword.size + 1;
                             randomPart = "";
                             numChars = numChars;
                             candidateChars = filterCharsToExclude(allChars, excludedChars); };

    value unshuffledPassword = fixedPartOfPassword + randomPart;

    assert(unshuffledPassword.string.size == numChars);

    "excluded chars contained"
    assert(! unshuffledPassword.any((char) => excludedChars.contains(char)));

    "Sizes not equal"
    assert(unshuffledPassword.size == numChars);

    value shuffledPassword =
        shuffleCharsRecursive(unshuffledPassword.string,"",unshuffledPassword.indexes().sequence());

    "Sizes not equal"
    assert(shuffledPassword.string.size == numChars);

    "set of characters not equal"
    assert(set(unshuffledPassword) == set(shuffledPassword));

    return shuffledPassword;
}

String passwordFragmentForRequirements(Random random, Character[] excludedChars)
    => String({filterAndUse(random,lowerCaseChars, excludedChars),
               filterAndUse(random,upperCaseChars,excludedChars),
               filterAndUse(random,numsAsChars,excludedChars),
               filterAndUse(random,specialChars,excludedChars)});

String randomPartOfPassword(Random random,
                            Integer index,
                            String randomPart,
                            Integer numChars,
                            Character[] candidateChars) {
    if(index <= numChars) {
        value candidateCharsIndex = random.nextInteger(candidateChars.size);
        assert(exists allChar = candidateChars[candidateCharsIndex]);
        return randomPartOfPassword{ random=random;
                                     index=index+1;
                                     randomPart = randomPart + allChar.string;
                                     numChars =numChars;
                                     candidateChars = candidateChars; };
    }

    return randomPart;
}

String shuffleCharsRecursive(String orig,String shuffledString,Integer[] remainingOrigIndexes) {
    value random = DefaultRandom();

    if (nonempty constRemainingIndexes = remainingOrigIndexes) {
        value randomIndex = random.nextInteger(orig.size);

        assert(exists nextChar = orig[randomIndex]);

        String newShuffledString;
        Integer[] newRemainingIndexes;

        if (constRemainingIndexes.contains(randomIndex)) {
            newShuffledString = shuffledString + nextChar.string;
            newRemainingIndexes = constRemainingIndexes.filter((index) => randomIndex != index).sequence();
        } else {
            newShuffledString = shuffledString;
            newRemainingIndexes = constRemainingIndexes;
        }

        return shuffleCharsRecursive{ orig=orig;
                                      shuffledString=newShuffledString;
                                      remainingOrigIndexes=newRemainingIndexes; };
    }

    return shuffledString;
}

Character filterAndUse(Random random, Character[] chars, Character[] excludedChars) {
    value charsToUse = filterCharsToExclude(chars, excludedChars);
    value charToUseIndex = random.nextInteger(charsToUse.size);
    assert( exists charToUse = charsToUse[charToUseIndex]);
    return charToUse;
}

Character[] filterCharsToExclude(Character[] chars, Character[] charsToExclude)
    => chars.filter((char) => ! charsToExclude.contains(char)).sequence();


Output:
2 passwords of size 8
------
o"{#3A]F
7OZ{k-!-
------
5 passwords of size 12
------
>jA%dQ[71RR{
e-(KQgjr!H1B
XF41ALUX&odg
)vpjL6YI=S38
[=e8."8!A*Dn
------
7 passwords of size 16
------
r/|'y0G&5:UA]AF#
75}P4L>^R0'#WkLR
bK2{Tg1del{pM/}n
86mz,.NfUB3b-A4)
4KOh7D5'W<oQ=/(e
s1b8~XA*f'y6mCA8
D^RwIB9-tL:_JTD7
------
2 passwords of size 16 exclude AiX24!~
------
8bx3$y=ZPdcT"Ls3
{M$EeG{x:]"6cZO|
"{?zn{80?g^eGK&w
u{VN#jy{TZpJ}5/F
5;_VaVG?^O:6xCo%
v:xx%Ht*Zc13GekC
Mg0M:BpCbz3O0BDo

Clojure

(ns pwdgen.core
  (:require [clojure.set :refer [difference]]
            [clojure.tools.cli :refer [parse-opts]])
  (:gen-class))

(def minimum-length 4)
(def cli-options
  [["-c" "--count NUMBER" "Number of passwords to generate"
    :default 1
    :parse-fn #(Integer/parseInt %)]
   ["-l" "--length NUMBER" "Length of the generated passwords"
    :default 8
    :parse-fn #(Integer/parseInt %)
    :validate [#(<= minimum-length %) (str "Must be greater than or equal to " minimum-length)]]
   ["-x", "--exclude-similar" "Exclude similar characters"]
   ["-h" "--help"]])

(def lowercase (map char (range (int \a) (inc (int \z)))))
(def uppercase (map char (range (int \A) (inc (int \Z)))))
(def numbers (map char (range (int \0) (inc (int \9)))))
(def specials (remove (set (concat lowercase uppercase numbers [\` \\])) (map char (range (int \!) (inc (int \~))))))
(def similar #{\I \l \1 \| \O \0 \5 \S \2 \Z})

(defn sanitize [coll options]
  (if (:exclude-similar options) (into '() (difference (set coll) similar)) coll))

(defn generate-password [options]
  (let [upper (rand-nth (sanitize uppercase options))
        lower (rand-nth (sanitize lowercase options))
        number (rand-nth (sanitize numbers options))
        special (rand-nth (sanitize specials options))
        combined (shuffle (sanitize (concat lowercase uppercase numbers specials) options))]
    (shuffle (into (list upper lower number special) (take (- (:length options) minimum-length) combined)))))

(defn -main [& args]
  (let [{:keys [options summary]} (parse-opts args cli-options)]
    (if (:help options) (println summary)
      (dotimes [n (:count options)]
        (println (apply str (generate-password options)))))))
Output:
$ lein run -- -h
  -c, --count NUMBER     1  Number of passwords to generate
  -l, --length NUMBER    8  Length of the generated passwords
  -x, --exclude-similar     Exclude similar characters
  -h, --help

$ lein run -l 20 -c 2
xn~a9UDE,rUm+x2w3o00
vlA|&fI>W57D^U:3g9L!

$ lein run --length 5 --count 3 -x
VT6-u
#kR6Y
Pj+4b

Commodore BASIC

Note that on line 220, the CLR statement is called prior to restarting the program to avoid a ?REDIM'D ARRAY ERROR if line 85 should execute. By default, single dimension arrays do not need to be DIMensioned if kept to 11 elements (0 through 10) or less. Line 85 checks for this.

1 rem password generator
2 rem rosetta code
10 g$(1)="abcdefghijklmnopqrstuvwxyz"
15 g$(2)="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
20 g$(3)="0123456789"
25 g$(4)="<>!@#$%^&*()[];:'.?/"
30 print chr$(147);chr$(14)
35 print "Password Generator":print
40 print "Press H for help, or any":print "other key to begin.":print
45 get k$:if k$="" then 45
50 if k$="h" then gosub 500
60 print chr$(147)
65 input "Enter password length: (6-30)";pl
70 if pl<6 or pl>30 then print "Out of range.":goto 65
75 print:input "How many passwords (1-20)";np
80 if np<1 or np>20 then print "Out of range.":goto 75
85 if np>10 then dim pw$(np)
90 if np*pl > 100 then print:print "Um... Ok, this might take a bit."
100 for pc=1 to np
105   for i=1 to 4:g(i)=0:next
110   tp$=""
112   for i=1 to pl
115     cg=int(rnd(1)*4)+1
120     cc=int(rnd(1)*len(g$(cg)))+1
125     tp$=tp$+mid$(g$(cg),cc,1)
130     g(cg)=g(cg)+1
135   next i
140   for i=1 to 4
145     if g(i)=0 then goto 110
150   next i
155   pw$(pc)=tp$
160 next pc
200 print chr$(147);"Password list:":print
205 for pc=1 to np:print pc;chr$(157);".";tab(6);pw$(pc):next pc
210 print:print "Again? (y/n)";
215 get k$:if k$<>"y" and k$<>"n" then 215
220 if k$="y" then clr:goto 10
225 end
500 rem *** help ***
505 print chr$(147);"This program will generate a password"
510 print "made up of each of the following"
515 print "character types:":print
520 print " - Uppercase Letter (A-Z)"
525 print " - Lowercase Letter (a-z)"
530 print " - Number (0-9)"
535 print " - Punctuation and Other Symbols"
540 print "   (e.g. # $ ! & [ . ;, etc.)"
545 print
550 print "You may choose how many total characters";
555 print "(up to 30) should be in the password, "
560 print "and how many passwords (up to 20) should";
565 print "be generated. The program ensures that "
570 print "there is at least one character from "
575 print "each of the character types in each "
580 print "password."
585 print
590 print "Note: You can edit the character lists"
595 print "on lines 10-25 to customize the"
600 print "selection pool."
605 print
610 print "Press any key to begin."
615 get k$:if k$="" then 615
620 return
Output:
Password Generator                      
                                        
Press H for help, or any                
other key to begin.                     

This program will generate a password   
made up of each of the following        
character types:                        
                                        
 - Uppercase Letter (A-Z)               
 - Lowercase Letter (a-z)               
 - Number (0-9)                         
 - Punctuation and Other Symbols        
   (e.g. # $ ! & [ . ;, etc.)           
                                        
You may choose how many total characters
(up to 30) should be in the password,   
and how many passwords (up to 20) should
be generated. The program ensures that  
there is at least one character from    
each of the character types in each     
password.                               
                                        
Note: You can edit the character lists  
on lines 10-25 to customize the         
selection pool.                         
                                        
Press any key to begin.
                                        
Enter password length: (6-30)? 12       
                                        
How many passwords (1-20)? 10           
                                        
Um... Ok, this might take a bit.

Password list:                          
                                        
 1.   K6GmO#[%lz7w                      
 2.   L6W(ln<Qldvy                      
 3.   lc48].KX<F$w                      
 4.   3$Z%;8/&70y5                      
 5.   <Ns@!W9#0[s3                      
 6.   )Sr!oZ<1pS1I                      
 7.   mhC4VTy]6a:7                      
 8.   !j4ntp8lJ1JY                      
 9.   ?b?1x48m$D65                      
 10.  Ooi;3W>[gr77                      
                                        
Again? (y/n)                            
ready.
█

Common Lisp

(defvar *lowercase* '(#\a #\b #\c #\d #\e #\f #\g #\h #\i #\j #\k #\l #\m
                      #\n #\o #\p #\q #\r #\s #\t #\u #\v #\w #\x #\y #\z))

(defvar *uppercase* '(#\A #\B #\C #\D #\E #\F #\G #\H #\I #\J #\K #\L #\M
                      #\N #\O #\P #\Q #\R #\S #\T #\U #\V #\W #\X #\Y #\Z))

(defvar *numbers* '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9))

(defvar *special-characters* '(#\! #\\ #\# #\$ #\% #\& #\' #\( #\) #\*
                              #\+ #\, #\- #\. #\/ #\: #\; #\< #\= #\>
                              #\? #\@ #\[ #\] #\^ #\_ #\{ #\| #\} #\~))

(defvar *similar-characters* '(#\I #\l #\1 #\| #\O #\0 #\5 #\S #\2 #\Z))

(defun make-readable (s)
  (remove-if (lambda (x) (member x *similar-characters*)) s))

(defun shuffle-list (input-list)
  (loop with l = (length input-list)
     for i below l
     do (rotatef (nth i input-list)
         (nth (random l) input-list)))
  input-list)

(defun generate-password (len human-readable)
  (let*
    ((upper (if human-readable (make-readable *uppercase*) *uppercase*))
    (lower (if human-readable (make-readable *lowercase*) *lowercase*))
    (number (if human-readable (make-readable *numbers*) *numbers*))
    (special (if human-readable (make-readable *special-characters*) *special-characters*))
    (character-groups (list upper lower number special))
    (initial-password (reduce (lambda (acc x)
      (cons (nth (random (length x)) x) acc))
      character-groups :initial-value NIL)))

    (coerce (shuffle-list (reduce (lambda (acc x)
      (declare (ignore x))
      (let ((group (nth (random (length character-groups)) character-groups)))
        (cons (nth (random (length group)) group) acc)))
      (make-list (- len 4)) :initial-value initial-password)) 'string)))

(defun main (len count &optional human-readable)
  (if (< len 4)
    (print "Length must be at least 4~%")
    (loop for x from 1 to count do
      (print (generate-password len human-readable)))))
Output:
$ (main 10 4 t)
"AV}HU&?8^s"
"y~868Wr3?j"
"4wy:Wy$zR8"
"Lx'6fsU+3t"
"&zXi3s71Jf"
"7ppunc1;G1"

Crystal

require "random/secure"

special_chars = true
similar = 0
require_groups = true
length = 20
count = 1

def show_usage
  puts <<-USAGE
  
       Passwords generator
       Usage: pass2 [count] [-l<length>] [-s{0|1|2}] [-ng] [-ns]

         count: number of passwords to be generated (default: 1)
         -l<length>: length of passwords (default: 20)
         -s{0|1|2}: exclude visually similar characters. 
                      0 - don't exclude (default)
                      1 - exclude 0, O, 1, I, l, |
                      2 - also exclude 2, Z, 5, S
        -ng: don''t require password to include character from every group
        -ns: don''t include special chars in password
        
        Default value of switches is choosen to match the task in page header, but I suggest to use the "-s1 -ng -ns".
       USAGE
end

count_set = false
begin
  ARGV.each do |arg|
    case arg
    when /-l(\d+)/
      length = $1.to_i
      raise "Error: minimal length is 4" if length < 4
    when /-s(\d)/
      similar = $1.to_i
      raise "Error: minimal length is 4" unless {0, 1, 2}.includes? similar
    when /-ng/
      require_groups = false
    when /-ns/
      special_chars = false
    when /(\d+)/
      raise "incorrect arguments" if count_set
      count_set = true
      count = $1.to_i
    else
      raise "incorrect argument"
    end
  end
rescue ex
  puts ex.message
  show_usage
  exit
end

# actual program
GROUPS = [('a'..'z').to_a, ('A'..'Z').to_a, ('0'..'9').to_a]
GROUPS << "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~".chars if special_chars

letters = GROUPS.flatten
letters -= "1l|I0O".chars if similar > 0
letters -= "5S2Z".chars if similar > 1

loop do
  s = Array(Char).new(length) { letters.sample(Random::Secure) }
  # it's better to just discard in order to don't lose enthropy
  next if require_groups && GROUPS.any? { |x| (s & x).size == 0 }
  puts s.join
  count -= 1
  break if count <= 0
end
Output:
user@laptop:/mnt/d/Projects/crystal$ ./pass2
0X{feScBZ_/b>7)>aL8)
user@laptop:/mnt/d/Projects/crystal$ ./pass2 -?
incorrect argument

Passwords generator
Usage: pass2 [count] [-l<length>] [-s{0|1|2}] [-ng] [-ns]

  count: number of passwords to be generated (default: 1)
  -l<length>: length of passwords (default: 20)
  -s{0|1|2}: exclude visually similar characters.
               0 - don't exclude (default)
               1 - exclude 0, O, 1, I, l, |
               2 - also exclude 2, Z, 5, S
 -ng: don't require password to include character from every group
 -ns: don't include special chars in password

 Default value of switches is choosen to match the task in page header, but I suggest to use the "-s1 -ng -ns".
user@laptop:/mnt/d/Projects/crystal$ ./pass2 10 -l20 -s2
j;K#3znen(j9%Bk6<tXf
k]h&i9[#["Pzr^zd<.9]
Xr%:7RP4%]^EXW?xB$A]
@{Jq/HWC%6.6+>BuGg/%
!99Y}8nEM$*hwRQ<-+Q>
*:"[r$tyf8zsv$%}n*M[
4nxHcMjn*v}j_qYon!qc
W#QqTu3NFF/m;Prs3]qe
i:_AEtzJQ^J]ek:G9[8=
=#_i3t]p}^gJP"z(&QaA
user@laptop:/mnt/d/Projects/crystal$ ./pass2 10 -l10 -s1 -ng -ns
fd5rHMaT6v
GzwccX2jQZ
Lx8rivLSLQ
a9NzxSQMhm
w5rrfpwJt8
RsbtZbgMxM
FcRPVxrxAA
s9fzZMwb8d
pKGyGPT7yN
ABZcXEPNWq
user@laptop:/mnt/d/Projects/crystal$

Elixir

defmodule Password do
  @lower Enum.map(?a..?z, &to_string([&1]))
  @upper Enum.map(?A..?Z, &to_string([&1]))
  @digit Enum.map(?0..?9, &to_string([&1]))
  @other ~S"""
!"#$%&'()*+,-./:;<=>?@[]^_{|}~
""" |> String.codepoints |> List.delete_at(-1)
  @all @lower ++ @upper ++ @digit ++ @other
  
  def generator do
    {len, num} = get_argv
    Enum.each(1..num, fn _ ->
      pswd = [Enum.random(@lower), Enum.random(@upper), Enum.random(@digit), Enum.random(@other)]
      IO.puts generator(len-4, pswd)
    end)
  end
  
  def generator(0, pswd), do: Enum.shuffle(pswd) |> Enum.join
  def generator(len, pswd), do: generator(len-1, [Enum.random(@all) | pswd])
  
  def get_argv do
    {len,num} = case System.argv do
      ["?"]     -> usage
      []        -> {8,1}
      [len]     -> {String.to_integer(len), 1}
      [len,num] -> {String.to_integer(len), String.to_integer(num)}
      _         -> usage
    end
    if len<4 or num<1, do: usage, else: {len,num}
  end
  
  defp usage do
    IO.puts ["Password generator\n",
             "Usage: [password length(=8)] [number of passwords to generate(=1)]"]
    exit(:normal)
  end
end

Password.generator
Output:
Elixir> elixir pswdgen.exs
Yu4*CSi|

Elixir> elixir pswdgen.exs 20 5
TWRfdAVYf_jl"Y~8gzx]
-)-D8Xz_fq5}c[STq("9
)xc30V06lEW&>k{9L_ON
GU$t*{887i5Ef@y(%VN'
}(b!m:DT%A7tLy[|qz{C

F#

The function

// A function to generate passwords of a given length. Nigel Galloway: May 2nd., 2018
let N = (set)"qwertyuiopasdfghjklzxcvbnm"
let I = (set)"QWERTYUIOPASDFGHJKLZXCVBNM"
let G = (set)"7894561230"
let E = (set)"""!"#$%&'()*+,-./:;<=>?@[]^_{|}~[||]"""
let L = Array.ofSeq (Set.unionMany [N;I;G;E])
let y = System.Random 23
let pWords n=
  let fN n = not (Set.isEmpty (Set.intersect N n )||Set.isEmpty (Set.intersect I n )||Set.isEmpty (Set.intersect G n )||Set.isEmpty (Set.intersect E n ))
  Seq.initInfinite(fun _->(set)(List.init n (fun _->L.[y.Next()%(Array.length L)])))|>Seq.filter fN|>Seq.map(Set.toArray >> System.String)

A possible use

Print 5 password of length 8

pWords 8 |> Seq.take 5 |> Seq.iter(printfn "%s")
Output:
+06:?H^w
$36=?Ofn
37<@TXk
,169GJWl
&6CDelow

Factor

Works with: Factor version 0.99 2020-01-23
USING: arrays assocs combinators command-line continuations io
kernel math math.parser multiline namespaces peg.ebnf
prettyprint random sequences ;
FROM: sets => without ;
IN: rosetta-code.password-generator

STRING: usage
password-generator generates random passwords.

 Commands:
   -l [int>=4]  Set password length (required)
   -c [int>0]   Set password count  (required)
   -s [int]     Set seed for random number generator
   -x           Exclude similar characters
      [empty]   Show this help
;

! Parse command line arguments into assoc
EBNF: parse-args [=[
  int  = "-"? [0-9]+ => [[ concat sift string>number ]]
  l    = "-l" " "~ int ?[ 4 >= ]?
  c    = "-c" " "~ int ?[ 0 >  ]?
  s    = "-s" " "~ int
  x    = "-x" => [[ 0 2array ]]
  arg  = l | c | s | x
  args = arg ((" "~ arg)+)?
       => [[ first2 [ 1array ] dip append ]]
]=]

CONSTANT: similar {
    "abcdefghijklmnopqrstuvwxyz"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "0123456789"
    "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~"
}

: dissimilar ( -- seq ) similar [ "Il1O05S2Z" without ] map ;

! Set seed if seed provided; otherwise use system rng.
: choose-rng ( args-assoc -- )
    "-s" of [ [ random-generator get ] dip seed-random drop ]
    [ system-random-generator get random-generator set ] if* ;

: choose-character-set ( args-assoc -- seq )
    "-x" of dissimilar similar ? ;

! Create a "base" for a password; one character from each
! category.
: <base> ( seq -- str ) [ random ] "" map-as ;

: password ( seq length -- str )
    4 - over concat [ random ] curry "" replicate-as
    [ <base> ] dip append randomize ;

: .passwords ( count seq length -- )
    [ password print ] 2curry times ;

: gen-pwds ( args-assoc -- )
    {
        [ choose-rng ]
        [ "-c" of ]
        [ choose-character-set ]
        [ "-l" of ]
    } cleave .passwords ;

: main ( -- )
    command-line get " " join
    [ parse-args gen-pwds ] [ 2drop usage print ] recover ;

MAIN: main
Output:
>password-generator
password-generator generates random passwords.

 Commands:
   -l [int>=4]  Set password length (required)
   -c [int>0]   Set password count  (required)
   -s [int]     Set seed for random number generator
   -x           Exclude similar characters
      [empty]   Show this help

>password-generator -l 10 -c 7 -s 33 -x
][#9vNKg%C
/%H|3mtg{H
-FsN'v,q:3
M"9B:8|z*(
8@Tb;zoF#i
^96AD+um@~
9L6Lqt|yh|


FreeBASIC

Translation of: Run BASIC
Dim As String charS(4)
charS(1) = "0123456789"
charS(2) = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
charS(3) = "abcdefghijklmnopqrstuvwxyz"
charS(4) = "!""#$%&'()*+,-./:;<=>?@[]^_{|}~"
charS(0) = charS(1) + charS(2) + charS(3) + charS(4)


Dim As Integer howBig, howMany
Do
    Print !"------ Password Generator ------\n"
    Input "Longitud de la contrase¤a (n>=4): ", howBig
    If howBig < 1 Then Sleep: End
    
    Input "Cantidad de contrase¤as (n>=1): ", howMany
Loop While howMany < 1

Print !"\nGeneradas"; howMany; " contrase¤as de"; howBig; " caracteres"

Dim As Integer i = 0
Dim As String password, Ok, w
While i < howMany
	password = ""
    Ok = "...."
    For j As Integer = 1 To howBig
        w = Mid(charS(0), Int(Rnd * Len(charS(0))) + 1, 1)
        For k As Byte = 1 To 4
            If Instr(charS(k), w) Then Ok = Left(Ok, k-1) + "*" + Mid(Ok, k+1)
        Next k
        password += w
    Next j
    If Ok = "****" Then
        i += 1
        Print Using "##. &"; i; password
    End If
Wend
Sleep
Output:
------ Password Generator ------

Longitud de la contraseña (n>=4): 5
Cantidad de contraseñas (n>=1): 2

Generadas 2 contraseñas de 5 caracteres
 1. 1qU+,
 2. v?X7s


FutureBasic

This compiles as a standalone Mac application that meets all the task requirements and options. Screenshot of compiled app shows output.

output file "Password Generator"
include "Tlbx GameplayKit.incl"

begin enum
  _mApplication
  _mFile
  _mEdit
end enum

begin enum 1
  _iSeparator
  _iPreferences
end enum

begin enum
  _iCreate
  _iSeparator2
  _iSave
  _iPrint
  _iSeparator4
  _iClose
end enum

_window = 1
begin enum output 1
  _passwordScroll
  _passwordView
  _offscreenPrintView
  _optionsHelp
  _checkOmitIs
  _checkOmitOs
  _checkOmitSs
  _checkOmit2s
  _charactersLongLabel
  _passwordLengthField
  _pwAmountLabel
  _pwAmountField
  _seedLabel
  _seedField
  _helpBtn
  _bottomLine
  _saveBtn
  _printBtn
  _createPasswordsBtn
end enum

_helpPopover = 2
begin enum 1
  _popoverLabel
end enum

_savePanel  = 1
_pwLenAlert = 2


void local fn BuildMenus
  // application
  menu _mApplication, _iSeparator
  menu _mApplication, _iPreferences,, @"Preferences…", @","
  
  // file
  menu _mFile, -1,, @"File"
  menu _mFile, _iCreate,, @"Create passwords", @"p"
  menu _mFile, _iSeparator2
  menu _mFile, _iSave,, @"Save", @"s"
  menu _mFile, _iPrint,, @"Print", @"p"
  menu _mFile, _iSeparator4
  menu _mFile, _iClose,, @"Close", @"w"
  MenuItemSetAction( _mFile, _iClose, @"performClose:" )
  
  editmenu _mEdit
end fn

void local fn BuildWindow
  long tag
  
  CGRect r = fn CGRectMake( 0, 0, 672, 460 )
  window _window, @"Rosetta Code Password Generator", r//, NSWindowStyleMaskTitled + NSWindowStyleMaskClosable + NSWindowStyleMaskMiniaturizable
  WindowSetContentMinSize( _window, fn CGSizeMake(310,386) )
  
  r = fn CGRectMake( 20, 73, 515, 370 )
  scrollview _passwordScroll, r, NSLineBorder,,_window
  ViewSetAutoresizingMask( _passwordScroll, NSViewWidthSizable + NSViewHeightSizable )
  
  textview _passwordView, r, _passwordScroll,, _window
  TextViewSetTextContainerInset( _passwordView, fn CGSizeMake( 10, 15 ) )
  TextSetFontWithName( _passwordView, @"Menlo", 13.0 )
  
  r = fn CGRectMake( -600, -600, 450, 405 )
  textview _offscreenPrintView, r,,, _window
  TextSetFontWithName( _offscreenPrintView, @"Menlo", 13.0 )
  TextSetColor( _offscreenPrintView, fn ColorBlack )
  TextViewSetBackgroundColor( _offscreenPrintView, fn ColorWhite )
  
  r = fn CGRectMake( 547, 424, 60, 16 )
  textlabel _optionsHelp, @"Exclude:", r, _window
  
  r = fn CGRectMake( 607, 425, 41, 14 )
  button _checkOmitIs, YES, NSControlStateValueOff, @"Il1", r, NSButtonTypeSwitch
  ViewSetToolTip( _checkOmitIs, @"Omit similar characters I, l and 1." )
  r = fn CGRectOffset( r, 0, -24 )
  button _checkOmitOs, YES ,NSControlStateValueOff, @"O0", r, NSButtonTypeSwitch
  ViewSetToolTip( _checkOmitOs, @"Omit similar characters O and 0." )
  r = fn CGRectOffset( r, 0, -24 )
  button _checkOmitSs, YES, NSControlStateValueOff, @"5S", r, NSButtonTypeSwitch
  ViewSetToolTip( _checkOmitSs, @"Omit similar characters 5 and S." )
  r = fn CGRectOffset( r, 0, -24 )
  button _checkOmit2s, YES, NSControlStateValueOff, @"2Z", r, NSButtonTypeSwitch
  ViewSetToolTip( _checkOmit2s, @"Omit similar characters 2 and Z." )
  
  r = fn CGRectMake( 549, 322, 103, 16 )
  textlabel _charactersLongLabel, @"Chars (4-50)", r, _window
  
  r = fn CGRectMake( 549, 298, 103, 21 )
  textfield _passwordLengthField, YES, @"25", r,_window
  TextFieldSetBordered( _passwordLengthField, YES )
  ControlSetAlignment(_passwordLengthField, NSTextAlignmentCenter )
  ControlSetFormat( _passwordLengthField, @"0123456789", YES, 2, 0 )
  ViewSetToolTip( _passwordLengthField, @"Set password length from 4 to 50." )
  
  r = fn CGRectMake( 549, 263, 103, 16 )
  textlabel _pwAmountLabel, @"Passwords:", r, _window
  
  r = fn CGRectMake( 549, 240, 103, 21 )
  textfield _pwAmountField, YES, @"100", r,_window
  TextFieldSetBordered( _pwAmountField, YES )
  ControlSetAlignment( _pwAmountField, NSTextAlignmentCenter )
  ControlSetFormat( _pwAmountField, @"0123456789", YES, 4, 0 )
  ViewSetToolTip( _pwAmountField, @"Enter number of passwords to generate." )
  
  r = fn CGRectMake( 549, 205, 103, 16 )
  textlabel _seedLabel, @"Seed value:", r, _window
  
  r = fn CGRectMake( 549, 182, 103, 21 )
  textfield _seedField, YES, , r,_window
  TextFieldSetBordered( _seedField, YES )
  ControlSetAlignment(_seedField, NSTextAlignmentCenter )
  ControlSetFormat( _seedField, @"0123456789", YES, 6, 0 )
  ViewSetToolTip( _seedField, @"Enter optional random seed number." )
  
  for tag = _optionsHelp to _seedField
    ViewSetAutoresizingMask( tag, NSViewMinXMargin + NSViewMinYMargin )
  next
  
  r = fn CGRectMake( 631, 70, 25, 25 )
  button _helpBtn, YES,,, r, NSButtonTypeMomentaryLight, NSBezelStyleHelpButton, _window
  ViewSetToolTip( _helpBtn, @"Click for application help instructions." )
  ViewSetAutoresizingMask( _helpBtn, NSViewMinXMargin + NSViewMaxYMargin )
  
  r = fn CGRectMake( 20, 55, 632, 5 )
  box _bottomline,, r, NSBoxSeparator
  ViewSetAutoresizingMask( _bottomline, NSViewWidthSizable + NSViewMaxYMargin )
  
  r = fn CGRectMake( 20, 15, 62, 32 )
  button _printBtn, YES, , @"Print…", r, NSButtonTypeMomentaryLight, NSBezelStyleRegularSquare, _window
  ViewSetAutoresizingMask( _printBtn, NSViewMaxXMargin + NSViewMaxYMargin )
  
  r = fn CGRectMake( 91, 15, 62, 32 )
  button _saveBtn, YES, , @"Save…", r, NSButtonTypeMomentaryLight, NSBezelStyleRegularSquare, _window
  ViewSetAutoresizingMask( _saveBtn, NSViewMaxXMargin + NSViewMaxYMargin )
  
  r = fn CGRectMake( 522, 15, 131, 32 )
  button _createPasswordsBtn, YES, , @"Create passwords", r, NSButtonTypeMomentaryLight, NSBezelStyleRegularSquare, _window
  ViewSetAutoresizingMask( _createPasswordsBtn, NSViewMinXMargin + NSViewMaxYMargin )
end fn

void local fn BuildPopover
  CFStringRef helpText = @"This application generates randomized passwords from 4 to 50 characters in length. "
  helpText = fn StringByAppendingString( helpText, @"Theoretically, the number generated is limited only by system memory.\n\n" )
  helpText = fn StringByAppendingString( helpText, @"Passwords will contain at least one each of the following character types:\n" )
  helpText = fn StringByAppendingString( helpText, @"\tLowercase letters\t\t:  a -> z\n" )
  helpText = fn StringByAppendingString( helpText, @"\tUppercase letters\t\t:  A -> Z\n" )
  helpText = fn StringByAppendingString( helpText, @"\tNumbers\t\t\t\t:  0 -> 9\n" )
  helpText = fn StringByAppendingString( helpText, @"\tSpecial characters\t:  !\"#$%&'()*+,-./:;<=>?@[]^_{|}~\n\n" )
  helpText = fn StringByAppendingString( helpText, @"You can use checkboxes to exclude visually similar characters: Il1  O0  5S  2Z.\n\n" )
  helpText = fn StringByAppendingString( helpText, @"This application offers two automatic levels of randomization. However you are " )
  helpText = fn StringByAppendingString( helpText, @"welcome to enter a custom randomizer seed number in the box provided.\n\n" )
  helpText = fn StringByAppendingString( helpText, @"Passwords can be copied to the pasteboard, saved to a text file, or printed." )
  popover _helpPopover, (0,0,395,365), NSPopoverBehaviorTransient
  textlabel _popoverLabel, helpText, (10,10,375,345)
end fn

void local fn OutOfBoundsAlert
  CFStringRef alertStr = @"Passwords must be at least four characters long, but no more than 50 characters."
  
  alert -_pwLenAlert,, @"Password length is out of bounds", alertStr, @"Okay", YES
  AlertButtonSetKeyEquivalent( _pwLenAlert, 1, @"\e" )
  AlertSetStyle( _pwLenAlert, NSAlertStyleWarning )
  alert _pwLenAlert
end fn


local fn BuildPassword as CFStringRef
  long i
  CFArrayRef    charArr = fn AppProperty( @"charArray" )
  CFStringRef   numbers = charArr[0]
  CFStringRef uppercase = charArr[1]
  CFStringRef lowercase = charArr[2]
  CFStringRef   symbols = charArr[3]
  
  // Omit confusing letters selected by user, if any
  if ( fn ButtonState( _checkOmitIs ) == NSControlStateValueOn )
    numbers   = fn StringByReplacingOccurrencesOfString(   numbers, @"1", @"" )
    uppercase = fn StringByReplacingOccurrencesOfString( uppercase, @"I", @"" )
    lowercase = fn StringByReplacingOccurrencesOfString( lowercase, @"l", @"" )
  end if
  
  if ( fn ButtonState( _checkOmitOs ) == NSControlStateValueOn )
    numbers   = fn StringByReplacingOccurrencesOfString(   numbers, @"0", @"" )
    uppercase = fn StringByReplacingOccurrencesOfString( uppercase, @"O", @"" )
  end if
  
  if( fn ButtonState( _checkOmitSs ) == NSControlStateValueOn )
    numbers   = fn StringByReplacingOccurrencesOfString(   numbers, @"5", @"" )
    uppercase = fn StringByReplacingOccurrencesOfString( uppercase, @"S", @"" )
  end if
  
  if ( fn ButtonState( _checkOmit2s ) == NSControlStateValueOn )
    numbers   = fn StringByReplacingOccurrencesOfString(   numbers, @"2", @"" )
    uppercase = fn StringByReplacingOccurrencesOfString( uppercase, @"Z", @"" )
  end if
  
  // Build string pool from other character sets
  CFStringRef allChars = fn StringWithFormat( @"%@%@%@%@", numbers, uppercase, lowercase, symbols )
  
  // Begin construction password string with single random character from each character set
  randomize
  CFMutableStringRef  pwStr = fn MutableStringWithCapacity(0)
  CFStringRef rndNumberChar = fn StringWithFormat( @"%c", fn StringCharacterAtindex(   numbers, rnd( len( numbers   ) -1 ) ) )
  CFStringRef  rndUCaseChar = fn StringWithFormat( @"%c", fn StringCharacterAtindex( uppercase, rnd( len( uppercase ) -1 ) ) )
  CFStringRef  rndLCaseChar = fn StringWithFormat( @"%c", fn StringCharacterAtindex( lowercase, rnd( len( lowercase ) -1 ) ) )
  CFStringRef rndSymbolChar = fn StringWithFormat( @"%c", fn StringCharacterAtindex(   symbols, rnd( len( symbols   ) -1 ) ) )
  
  // Add first four randomized characters to password string
  MutableStringAppendString( pwStr, fn StringWithFormat( @"%@%@%@%@", rndNumberChar, rndUCaseChar, rndLCaseChar, rndSymbolChar ) )
  
  // Build array of characters for shuffling
  CFMutableArrayRef mutArr = fn MutableArrayWithCapacity(0)
  for i = 0 to len(allChars) - 1
    unichar tempUni = fn StringCharacterAtIndex( allChars, i )
    CFStringRef s = fn StringWithFormat( @"%c", tempUni )
    MutableArrayInsertObjectAtIndex( mutArr, s, i )
  next
  
  // Shuffle character array for randomness
  CFArrayRef rndStrArr = fn GKRandomSourceArrayByShufflingObjectsInArray( fn GKRandomSourceInit, mutArr )
  CFStringRef rndStr = fn ArrayComponentsJoinedByString( rndStrArr, @"" )
  
  long pwLength = fn StringIntegerValue( fn ControlStringValue( _passwordLengthField ) )
  
  // Subtract 4 for mandatory charaacters already set
  rndStr = fn StringSubstringToIndex( rndStr, pwLength - 4 )
  MutableStringAppendString( pwStr, rndStr )
end fn = pwStr


void local fn RandomizeWithSeed
  CFStringRef seedStr = fn ControlStringValue( _seedField )
  
  if ( len(seedStr) > 0 )
    long  seedNum = fn StringIntegerValue( seedStr )
    randomize seedNum
  else
    exit fn
  end if
end fn


void local fn CreatePasswords
  NSInteger i
  CFMutableStringRef passwords = fn MutableStringWithCapacity(0)
  long            numberNeeded = fn StringIntegerValue( fn ControlStringValue( _pwAmountField ) )
  
  // Get length of password designated by user
  long pwLength = fn StringIntegerValue( fn ControlStringValue( _passwordLengthField ) )
  
  if ( pwLength > 50 ) or ( pwLength < 4 )
    fn OutOfBoundsAlert : exit fn
  end if
  
  fn RandomizeWithSeed
  
  for i = 1 to numberNeeded
    MutableStringAppendString( passwords, fn StringWithFormat( @"%4d. %@%@\n", i, fn BuildPassword, @"\n" ) )
  next
  TextSetString( _passwordView, passwords )
end fn


void local fn SaveFile
  savepanel -_savePanel, @"Save file...", @"public.plain-text",,,, _true
  SavePanelSetCanCreateDirectories( _savePanel, YES )
  SavePanelSetAllowedFileTypes( _savePanel, @[@"txt"] )
  SavePanelSetExtensionHidden( _savePanel, NO )
  // Run savepanel; action captured in fn DoDialog
  savepanel _savePanel
end fn


void local fn SetViewText( url as CFURLRef )
  CFStringRef tempStr = fn StringWithContentsOfURL( url, NSUTF8StringEncoding, NULL )
  WindowSetTitleWithRepresentedURL( _window, url )
  TextSetString( _passwordView, tempStr )
end fn


void local fn PrintView( tag as long )
  TextSetString( _offscreenPrintView, fn TextString( tag ) )
  ViewPrint( _offscreenPrintView )
end fn

// Build character arrays at launch and save as application property
void local fn CreateCharactersDictionary
  CFArrayRef charArray = @[¬
  @"0123456789",¬
  @"ABCDEFGHIJKLMNOPQRSTUVWXYZ",¬
  @"abcdefghijklmnopqrstuvwxyz",¬
  @"!\"#$%&'()*+,-./:;<=>?@[]^_{|}~"]
  AppSetProperty( @"charArray", charArray )
end fn


void local fn DoAppEvent( ev as long )
  select (ev)
    case _appDidFinishLaunching
      fn CreateCharactersDictionary
      fn BuildMenus
      fn BuildPopover
      fn BuildWindow
    case _appShouldTerminateAfterLastWindowClosed
      AppEventSetBool(YES)
  end select
end fn


void local fn DoMenu( menuID as long, itemID as long )
  select (menuID)
    case _mApplication
      select (itemID)
        case _iPreferences  // show preferences window
      end select
    case _mFile
      select (itemID)
        case _iCreate : fn CreatePasswords
        case _iSave   : fn SaveFile
        case _iPrint  : fn PrintView( _passwordView )
      end select
  end select
end fn


void local fn DoDialog( ev as NSInteger, tag as NSInteger, wnd as NSInteger, obj as CFTypeRef )
  select ( ev )
    case _btnClick
      select ( tag )
        case _createPasswordsBtn : fn CreatePasswords
        case _saveBtn            : fn SaveFile
        case _printBtn           : fn PrintView( _passwordView )
        case _helpBtn            : PopoverShow( _helpPopover, CGRectZero, _helpBtn, CGRectMaxXEdge )
      end select
  end select
end fn

on appEvent fn DoAppEvent
on menu fn DoMenu
on dialog fn DoDialog

HandleEvents
Output:

Gambas

[https:c/gambas-playground.proko.eu/?gist=0ef1242c761d8a39297fb913fc6a56c0 Click this link to run this code]

' Gambas module file

' INSTRUCTIONS
' I have not used a GUI as you could not run this in the 'Gambas Playground'
' Click on the link above to run this program
' The user can specify the password length and the number of passwords
' to generate by altering the values of the 2 lines below.

Public Sub Main()
Dim siPasswordLength As Short = 20                                      'Password length
Dim siPasswordQuantity As Short = 20                                    'Password quantity
Dim sLower As String = "abcdefghijklmnopqrstuvwxyz"                     'Lower case characters
Dim sUpper As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"                     'Upper case characters
Dim sNumber As String = "1234567890"                                    'Numbers
Dim sOther As String = "'!#$%&'()*+,-./:;<=>?@[]^_{|}~" & Chr(34)       'Other characters + quote
Dim sNoGo As String[] = ["I1", "1I", "l1", "1l", "Il", 
                        "lI", "O0", "0O", "S5", "5S", "Z2", "2Z"]       'Undesirable string combinations (can be added to if required)
Dim sData As String = sLower & sUpper & sNumber & sOther                'Create 1 string to pick the password characters from
Dim sToCheck, sPassword As String                                       'To hold a possible password for checking, to hold the passwords
Dim siCount, siLoop, siCounter As Short                                 'Various counters
Dim bPass As Boolean                                                    'To Pass or not to Pass!

For siCount = 1 To siPasswordQuantity                                   'Loop the amount of passwords required
  For siLoop = 1 To siPasswordLength                                    'Loop for each charater of the required length
    sToCheck &= Mid(sData, Rand(1, Len(sData)), 1)                      'Get a random character from sData
  Next

  bPass = False                                                         'Set bPass to False
  For siCounter = 1 To Len(sToCheck)                                    'Loop through each character in the generated password
    If InStr(sLower, Mid(sToCheck, siCounter, 1)) Then bPass = True     'If a LOWER CASE letter is included set bPass to True
  Next

  If bPass Then                                                         'If bPass is True then
    bPass = False                                                       'bPass is False
    For siCounter = 1 To Len(sToCheck)                                  'Loop through each character in the generated password
      If InStr(sUpper, Mid(sToCheck, siCounter, 1)) Then bPass = True   'If an UPPER CASE letter is included set bPass to True
    Next
  End If
  
  If bPass Then                                                         'If bPass is True then
    bPass = False                                                       'bPass is False
    For siCounter = 1 To Len(sToCheck)                                  'Loop through each character in the generated password
      If InStr(sNumber, Mid(sToCheck, siCounter, 1)) Then bPass = True  'If a NUMBER is included set bPass to True
    Next
  End If

  If bPass Then                                                         'If bPass is True then
    bPass = False                                                       'bPass is False
    For siCounter = 1 To Len(sToCheck)                                  'Loop through each character in the generated password
      If InStr(sOther, Mid(sToCheck, siCounter, 1)) Then bPass = True   'If an 'OTHER CHARACTER' is included set bPass to True
    Next
  End If

  If bPass Then
    For siCounter = 1 To sNoGo.Max                                      'Loop through each undesirable strings e.g. "0O"
      If InStr(sToCheck, sNoGo[siCounter]) Then bPass = False           'If an undesirable combination is located then set bPass to False
    Next
  Endif

  If bPass = True Then                                                  'If bPass is True (all checks have been passed) then
    sPassword &= sToCheck & gb.NewLine                                  'Add the new password to sPassword with a newline
  Else                                                                  'Else
    Dec siCount                                                         'Decrease the loop counter by one
  Endif
  sToCheck = ""                                                         'Clear sToCheck
Next

Print sPassword                                                         'Print the password list

End

Output:

+j<Zwk,h&0-Bb976hs^B
HCMC2T,rI_&&wBjavysX
/OS6'd-+o|:'[L$1|u56
DP/<$27oa/c)[/t1YI@F
k@fu3yk=vsXsA!3rENN^
7~V?DDZl$W>mwA'tn5~9
:K]LWNxdrUmhwj_2>-85
,/NLH}#r8DeytFkFl.[>
6&mgbo11r)IbI;n@RDal
K$0m^J0r3fk~r56?H+5:
;"AT-D9m^*VKVM"0Gx|}
8k}IT{DAV|P!'wl}64g$
jq3G$h^D&19>?+_9q^:Z
+O$0z;1zN5y'*(79H$Q,

Go

package main

import (
	"crypto/rand"
	"math/big"
	"strings"
	"flag"
	"math"
        "fmt" 
)

var lowercase = "abcdefghijklmnopqrstuvwxyz"
var uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
var numbers = "0123456789"
var signs = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~"
var similar = "Il1O05S2Z"

func check(e error){
	if e != nil {
		panic(e)
	}
}

func randstr(length int, alphastr string) string{
	alphabet := []byte(alphastr)
	pass := make([]byte,length)
	for i := 0; i < length; i++ {
		bign, err := rand.Int(rand.Reader, big.NewInt(int64(len(alphabet))))
		check(err)
		n := bign.Int64()
		pass[i] = alphabet[n]
	}
	return string(pass)
}

func verify(pass string,checkUpper bool,checkLower bool, checkNumber bool, checkSign bool) bool{
	isValid := true
	if(checkUpper){
		isValid = isValid && strings.ContainsAny(pass,uppercase)
	}
	if(checkLower){
		isValid = isValid && strings.ContainsAny(pass,lowercase)
	}
	if(checkNumber){
		isValid = isValid && strings.ContainsAny(pass,numbers)
	}
	if(checkSign){
		isValid = isValid && strings.ContainsAny(pass,signs)
	}
	return isValid
}


func main() {
	passCount := flag.Int("pc", 6, "Number of passwords")
	passLength := flag.Int("pl", 10, "Passwordlength")
	useUpper := flag.Bool("upper", true, "Enables or disables uppercase letters")
	useLower := flag.Bool("lower", true, "Enables or disables lowercase letters")
	useSign := flag.Bool("sign", true, "Enables or disables signs")
	useNumbers := flag.Bool("number", true, "Enables or disables numbers")
	useSimilar := flag.Bool("similar", true,"Enables or disables visually similar characters")
	flag.Parse()

	passAlphabet := ""
	if *useUpper {
		passAlphabet += uppercase
	}
	if *useLower {
		passAlphabet += lowercase
	}
	if *useSign {
		passAlphabet += signs
	}
	if *useNumbers {
		passAlphabet += numbers
	}
	if !*useSimilar {
		for _, r := range similar{
			passAlphabet = strings.Replace(passAlphabet,string(r),"", 1)
		}
	}
	fmt.Printf("Generating passwords with an average entropy of %.1f bits \n", math.Log2(float64(len(passAlphabet))) * float64(*passLength))
	for i := 0; i < *passCount;i++{
		passFound := false
		pass := ""
		for(!passFound){
			pass = randstr(*passLength,passAlphabet)
			passFound = verify(pass,*useUpper,*useLower,*useNumbers,*useSign)
		}
		fmt.Println(pass)
	}
}
Output:
Generating passwords with an average entropy of 65.2 bits 
.JJ%z({4,x
.[n9d7,f8U
1Y:)pL7&R6
:~+I5xCh1#
%6|_gJ!"}m
jOU8z^f_1J

Haskell

The password generation process.

The function password for given length and a list of char sets which should be included, generates random password.

import Control.Monad
import Control.Monad.Random
import Data.List

password :: MonadRandom m => [String] -> Int -> m String
password charSets n = do
  parts <- getPartition n
  chars <- zipWithM replicateM parts (uniform <$> charSets)
  shuffle (concat chars)
  where
    getPartition n = adjust <$> replicateM (k-1) (getRandomR (1, n `div` k))
    k = length charSets
    adjust p = (n - sum p) : p

shuffle :: (Eq a, MonadRandom m) => [a] -> m [a]
shuffle [] = pure []
shuffle lst = do
  x <- uniform lst
  xs <- shuffle (delete x lst)
  return (x : xs)

For example:

λ> password ["abcxyz","123"] 10
"x3b1y2ac3z"

λ> replicateM 5 (password ["abcxyz","123","#!"] 8)
["y!b#zyx2","xzcx!1xb","3zcax#aa","!ca1a2c#","#21a#zyc"]

User interface (uses a powerful and easy-to-use command-line option parser).

import Options

data Opts = Opts { optLength :: Int
                 , optCount :: Int
                 , optReadable :: Bool }

instance Options Opts where
    defineOptions = Opts <$>
      simpleOption "length" 8 "password length" <*>
      simpleOption "count" 1 "number of passwords to be generated" <*>
      simpleOption "readable" False "Whether to use only readable characters"

main = runCommand $ \opts args -> do
  let n = optCount opts
      l = optLength opts
      s = if (optReadable opts)
          then zipWith (\\) charSets visualySimilar
          else charSets
  res <- replicateM n (password s (max 4 l))
  mapM_ putStrLn res
  where
    charSets = [ ['a'..'z'] 
               , ['A'..'Z'] 
               , ['0'..'9'] 
               , "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~" ]

    visualySimilar = ["l","IOSZ","012","!|.,"]
Output:
$ ./password -h
Help Options:
  -h, --help
    Show option summary.
  --help-all
    Show all help options.

Application Options:
  --length :: int
    password length
    default: 8
  --count :: int
    number of passwords to be generated
    default: 1
  --readable :: bool
    whether to avoid visually similar characters
    default: false

$ ./password
PBpx#9hj

$ ./password --length 10 --count 10
2gso<zJtn@
sv:W7inoWk
fovo0mUO:q
[4bC4liy,k
s?cwr2JbTm
z2mrZpav!x
2#bq0rwoOI
W*pv19wrjb
Yx2j)f6is"
j6YM0_qd&v

$ ./password --readable --length 10 --count 10
bsx<xL8aA"
c&~E6ja5oY
Ri7tg7h$hz
oekF}9ab6v
jmmK5_cii7
P@xcqspY8d
kdnkgJ*Ak8
ue~uAuN7g+
gzbkK9$6ye
m#jdQan94z

J

Implementation:

thru=: <. + i.@(+*)@-~
chr=: a.&i.

lower=: 'a' thru&.chr 'z'
upper=: 'A' thru&.chr 'Z'
digit=: '0' thru&.chr '9'
other=: ('!' thru&.chr '~')-.lower,upper,digit,'`\'
all=: lower,upper,digit,other

pwgen =:verb define"0 :: pwhelp
  NB. pick one of each, remainder from all, then shuffle
  (?~y) { (?@# { ])every lower;upper;digit;other;(y-4)#<all
:
  pwgen x#y
)

pwhelp =:echo bind (noun define)
  [x] pwgen y - generates passwords of length y
  optional x says how many to generate (if you want more than 1)

  y must be at least 4 because 
  passwords must contain four different kinds of characters.
)

Example use (from J command line):

   pwgen'help'
  [x] pwgen y - generates passwords of length y
  optional x says how many to generate (if you want more than 1)

  y must be at least 4 because 
  passwords must contain four different kinds of characters.

   pwgen 10
S%"x8X0}:K
   5 pwgen 10
+u.9(XDM.O
]a@Yb6j~DI
Oo?|2oc4yi
9V9[EJ:Txs
$vYd(>4L:m

Java

Works with: Java version 7
import java.util.*;

public class PasswordGenerator {
    final static Random rand = new Random();

    public static void main(String[] args) {
        int num, len;

        try {
            if (args.length != 2)
                throw new IllegalArgumentException();

            len = Integer.parseInt(args[0]);
            if (len < 4 || len > 16)
                throw new IllegalArgumentException();

            num = Integer.parseInt(args[1]);
            if (num < 1 || num > 10)
                throw new IllegalArgumentException();

            for (String pw : generatePasswords(num, len))
                System.out.println(pw);

        } catch (IllegalArgumentException e) {
            String s = "Provide the length of the passwords (min 4, max 16) you "
                    + "want to generate,\nand how many (min 1, max 10)";
            System.out.println(s);
        }
    }

    private static List<String> generatePasswords(int num, int len) {
        final String s = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~";

        List<String> result = new ArrayList<>();

        for (int i = 0; i < num; i++) {
            StringBuilder sb = new StringBuilder();
            sb.append(s.charAt(rand.nextInt(s.length())));
            sb.append((char) (rand.nextInt(10) + '0'));
            sb.append((char) (rand.nextInt(26) + 'a'));
            sb.append((char) (rand.nextInt(26) + 'A'));

            for (int j = 4; j < len; j++) {
                int r = rand.nextInt(93) + '!';
                if (r == 92 || r == 96) {
                    j--;
                } else {
                    sb.append((char) r);
                }
            }
            result.add(shuffle(sb));
        }
        return result;
    }

    public static String shuffle(StringBuilder sb) {
        int len = sb.length();
        for (int i = len - 1; i > 0; i--) {
            int r = rand.nextInt(i);
            char tmp = sb.charAt(i);
            sb.setCharAt(i, sb.charAt(r));
            sb.setCharAt(r, tmp);
        }
        return sb.toString();
    }
}
7V;m
4u>I
J2$s
I8~h

2Q4,dD.Y'z>8
<|U)qS7S9d_M
c4*hLisq^e26
'H$1e)BpYh*8
*'R8yEmvh9v]

JavaScript

String.prototype.shuffle = function() {
  return this.split('').sort(() => Math.random() - .5).join('');
}

function createPwd(opts = {}) {
  let len    = opts.len || 5,                       // password length
      num    = opts.num || 1,                       // number of outputs
      noSims = opts.noSims == false ? false : true, // exclude similar?
      out = [],
      cur, i;

  let chars = [
    'abcdefghijkmnopqrstuvwxyz'.split(''),
    'ABCDEFGHJKLMNPQRTUVWXY'.split(''),
    '346789'.split(''),
    '!"#$%&()*+,-./:;<=>?@[]^_{|}'.split('')
  ];

  if (!noSims) {
    chars[0].push('l');
    chars[1] = chars[1].concat('IOSZ'.split(''));
    chars[2] = chars[2].concat('1250'.split(''));
  }

  if (len < 4) {
    console.log('Password length changed to 4 (minimum)');
    len = 4;
  }

  while (out.length < num) {
    cur = '';
    // basic requirement
    for (i = 0; i < 4; i++)
      cur += chars[i][Math.floor(Math.random() * chars[i].length)];

    while (cur.length < len) {
      let rnd = Math.floor(Math.random() * chars.length);
      cur += chars[rnd][Math.floor(Math.random() * chars[rnd].length)];
    }
    out.push(cur);
  }

  for (i = 0; i < out.length; i++) out[i] = out[i].shuffle();

  if (out.length == 1) return out[0];
  return out;
}

// testing
console.log( createPwd() );
console.log( createPwd( {len: 20}) );
console.log( createPwd( {len: 20, num: 2}) );
console.log( createPwd( {len: 20, num: 2, noSims: false}) );
Output:

> Q^g"7 > NP3*fb3L!9++Yf)sx/m# > Array [ "]7Qs9/7En9d,!!j.U6pT", "9LDc-is6tCa6L88dKy6H" ] > Array [ "yI7<)d5a5#4R>v4aLG8.", "s<GJ59||J]vS%_gUf4Xs" ]


jq

Works with: jq

Works with gojq, the Go implementation of jq

Adapted from Julia

The following assumes that an external source of randomness such as /dev/urandom is available and that jq is invoked along the lines of the following:

< /dev/urandom tr -cd '0-9' | fold -w 1 | jq -MRnr -f password-generator.jq
# Output: a prn in range(0;$n) where $n is `.`
def prn:
  if . == 1 then 0
  else . as $n
  | ([1, (($n-1)|tostring|length)]|max) as $w
  | [limit($w; inputs)] | join("") | tonumber
  | if . < $n then . else ($n | prn) end
  end;

# Input: an array
# Output: an array, being a selection of $k elements from . chosen with replacement
def prns($k):
  . as $in
  | length as $n
  | [range(0; $k) | $in[$n|prn]];

def knuthShuffle:
  length as $n
  | if $n <= 1 then .
    else {i: $n, a: .}
    | until(.i ==  0;
        .i += -1
        | (.i + 1 | prn) as $j
        | .a[.i] as $t
        | .a[.i] = .a[$j]
        | .a[$j] = $t)
    | .a 
    end;

# Generate a single password of length $len >= 4;
# certain confusable characters are only allowed iff $simchars is truthy.
def passgen($len; $simchars):
  def stoa: explode | map([.]|implode);
  
  if $len < 4 then "length must be at least 4" | error
  else
    { DIGIT: ("0123456789" | stoa),
      UPPER: [range(65;91) | [.] | implode],  # A-Z
      LOWER: [range(97;123) | [.] | implode], # a-z
      OTHER: ("!\"#$%&'()*+,-./:;<=>?@[]^_{|}~" | stoa) }
  | if $simchars|not
    then .DIGIT |= . - ["0", "1", "2", "5"]
    |    .UPPER |= . - ["O", "I", "Z", "S"]
    |    .LOWER |= . -  ["l"]
    end
  | (reduce (.DIGIT, .UPPER, .LOWER, .OTHER) as $set ([];
                 . + ($set | prns(1)))) +
    (.DIGIT + .UPPER + .LOWER + .OTHER | prns($len - 4))
  | knuthShuffle
  | join("")
  end ;

def passgen($len):
  passgen($len; true);

# Generate a stream of $npass passwords, each of length $len;
# certain confusable characters are only allowed iff $simchars is truthy.
def passgen($len; $npass; $seed; $simchars):
  if ($seed | type) == "number" and $seed > 0 then $seed | prn else null end
  | range(0; $npass)
  | passgen($len; $simchars) ;


### Examples:
"Without restriction:", passgen(12; 5; null; true),
"",
"Certain confusable characters are disallowed:", passgen(12; 5; null; false)
Output:
Without restriction:
yT8+9t7=wfEn
#]j<HIpThJ6A
|~O{psk*[5)I
w_(N%QrI5:5#
$o3sfdKv"'9~

Certain confusable characters are disallowed:
>oXgj>H9wX^[
a^JR+v!bk6GU
7$~yp?YG]G|E
!/_MM_g.p{a4
iD?+xU+!A4]R

Julia

Works with: Julia version 0.6
function passgen(len::Integer; simchars::Bool=true)::String
    if len < 4; error("length must be at least 4") end
    # Definitions
    DIGIT = collect('0':'9')
    UPPER = collect('A':'Z')
    LOWER = collect('a':'z')
    OTHER = collect("!\"#\$%&'()*+,-./:;<=>?@[]^_{|}~")
    if !simchars
        setdiff!(DIGIT, ['0', '1', '2', '5'])
        setdiff!(UPPER, ['O', 'I', 'Z', 'S'])
        setdiff!(LOWER, [     'l'])
    end
    ALL = union(DIGIT, UPPER, LOWER, OTHER)

    chars = collect(rand(set) for set in (DIGIT, UPPER, LOWER, OTHER))
    len -= 4
    append!(chars, rand(ALL, len))

    return join(shuffle!(chars))
end

function passgen(io::IO, len::Int=8, npass::Int=1; seed::Int=-1, simchars::Bool=true)::Vector{String}
    if seed > -1; srand(seed) end
    passwords = collect(passgen(len; simchars=simchars) for i in 1:npass)
    writedlm(io, passwords, '\n')
    return passwords
end

passgen(stdout, 10, 12; seed = 1)
Output:
p-7w^hK~8r
fDU~f^b5)J
j5.phuRNgB
[/0'0AUUFx
8h;BPr$#[[
R*8h<xAetD
ZelB^Y8lT0
"c4S""j/2QoZ"
~C-o18d6eH
TdrmQ(7?1~
^UH&Iu1*l9
sg8SAF;<4y

Kotlin

// version 1.1.4-3

import java.util.Random
import java.io.File

val r = Random()
val rr = Random()  // use a separate generator for shuffles
val ls = System.getProperty("line.separator") 

var lower = "abcdefghijklmnopqrstuvwxyz"
var upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
var digit = "0123456789"
var other = """!"#$%&'()*+,-./:;<=>?@[]^_{|}~"""

val exclChars = arrayOf(
    "'I', 'l' and '1'", 
    "'O' and '0'     ",
    "'5' and 'S'     ",
    "'2' and 'Z'     "
)

fun String.shuffle(): String {
    val sb = StringBuilder(this)
    var n = sb.length
    while (n > 1) {
        val k = rr.nextInt(n--)
        val t = sb[n]
        sb[n] = sb[k]
        sb[k] = t
    }
    return sb.toString()
}

fun generatePasswords(pwdLen: Int, pwdNum: Int, toConsole: Boolean, toFile: Boolean) {
    val sb = StringBuilder()
    val ll = lower.length
    val ul = upper.length
    val dl = digit.length
    val ol = other.length
    val tl = ll + ul + dl + ol 
    var fw = if (toFile) File("pwds.txt").writer() else null
  
    if (toConsole) println("\nThe generated passwords are:")
    for (i in 0 until pwdNum) {
        sb.setLength(0)
        sb.append(lower[r.nextInt(ll)])
        sb.append(upper[r.nextInt(ul)])
        sb.append(digit[r.nextInt(dl)])
        sb.append(other[r.nextInt(ol)])
       
        for (j in 0 until pwdLen - 4) {
            val k = r.nextInt(tl)
            sb.append(when (k) {
                in 0 until ll -> lower[k]
                in ll until ll + ul -> upper[k - ll]
                in ll + ul until tl - ol -> digit[k - ll - ul]
                else -> other[tl - 1 - k]
            })
        }
        var pwd = sb.toString()
        repeat(5) { pwd = pwd.shuffle() } // shuffle 5 times say
        if (toConsole) println("  ${"%2d".format(i + 1)}:  $pwd")
        if (toFile) {
            fw!!.write(pwd)
            if (i < pwdNum - 1) fw.write(ls)
        }
    }
    if (toFile) {
       println("\nThe generated passwords have been written to the file pwds.txt") 
       fw!!.close()
    } 
}

fun printHelp() {
    println(""" 
        |This program generates up to 99 passwords of between 5 and 20 characters in 
        |length.
        |
        |You will be prompted for the values of all parameters when the program is run 
        |- there are no command line options to memorize.
        |
        |The passwords can either be written to the console or to a file (pwds.txt), 
        |or both.
        |
        |The passwords must contain at least one each of the following character types:
        |   lower-case letters :  a -> z
        |   upper-case letters :  A -> Z
        |   digits             :  0 -> 9
        |   other characters   :  !"#$%&'()*+,-./:;<=>?@[]^_{|}~
        |
        |Optionally, a seed can be set for the random generator 
        |(any non-zero Long integer) otherwise the default seed will be used. 
        |Even if the same seed is set, the passwords won't necessarily be exactly
        |the same on each run as additional random shuffles are always performed.
        |
        |You can also specify that various sets of visually similar characters
        |will be excluded (or not) from the passwords, namely: Il1  O0  5S  2Z
        | 
        |Finally, the only command line options permitted are -h and -help which
        |will display this page and then exit.
        |
        |Any other command line parameters will simply be ignored and the program
        |will be run normally.
        |
    """.trimMargin())
}   
               
fun main(args: Array<String>) {
    if (args.size == 1 && (args[0] == "-h" || args[0] == "-help")) {
       printHelp()
       return
    }
        
    println("Please enter the following and press return after each one")
   
    var pwdLen: Int?
    do {
       print("  Password length (5 to 20)     : ")
       pwdLen = readLine()!!.toIntOrNull() ?: 0       
    }
    while (pwdLen !in 5..20)

    var pwdNum: Int?
    do {
       print("  Number to generate (1 to 99)  : ")
       pwdNum = readLine()!!.toIntOrNull() ?: 0       
    }
    while (pwdNum !in 1..99)
    
    var seed: Long?
    do {
       print("  Seed value (0 to use default) : ")
       seed = readLine()!!.toLongOrNull()       
    }
    while (seed == null)
    if (seed != 0L) r.setSeed(seed)

    println("  Exclude the following visually similar characters")
    for (i in 0..3) {
        var yn: String
        do {
            print("    ${exclChars[i]} y/n : ")
            yn = readLine()!!.toLowerCase()
        }
        while (yn != "y" && yn != "n")
        if (yn == "y") {
            when (i) {
                0 -> {
                    upper = upper.replace("I", "")
                    lower = lower.replace("l", "")
                    digit = digit.replace("1", "")
                }

                1 -> {
                    upper = upper.replace("O", "")
                    digit = digit.replace("0", "")
                }

                2 -> {
                    upper = upper.replace("S", "")
                    digit = digit.replace("5", "")
                }

                3 -> {
                    upper = upper.replace("Z", "")
                    digit = digit.replace("2", "")
                }
            }
        }
    }
   
    var toConsole: Boolean?
    do {
        print("  Write to console   y/n : ")
        val t = readLine()!!
        toConsole = if (t == "y") true else if (t == "n") false else null
    }
    while (toConsole == null)

    var toFile: Boolean? = true
    if (toConsole) {
        do {
            print("  Write to file      y/n : ")
            val t = readLine()!!
            toFile = if (t == "y") true else if (t == "n") false else null
        }
        while (toFile == null)
    }
 
    generatePasswords(pwdLen!!, pwdNum!!, toConsole, toFile!!)
}

Sample input and output:

Please enter the following and press return after each one
  Password length (5 to 20)     : 8
  Number to generate (1 to 99)  : 10
  Seed value (0 to use default) : 0
  Exclude the following visually similar characters
    'I', 'l' and '1' y/n : n
    'O' and '0'      y/n : n
    '5' and 'S'      y/n : n
    '2' and 'Z'      y/n : n
  Write to console   y/n : y
  Write to file      y/n : y

The generated passwords are:
   1:  n09&VswT
   2:  b/:7XL'r
   3:  k1<M2T[/
   4:  1uWCkx6*
   5:  Rr?/4)'d
   6:  _i5,%jAy
   7:  1(Jn]ZD+
   8:  qa1lGNo)
   9:  cfr9{}{K
  10:  OPO3b{tY

The generated passwords have been written to the file pwds.txt

Lua

function randPW (length)
    local index, pw, rnd = 0, ""
    local chars = {
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
        "abcdefghijklmnopqrstuvwxyz",
        "0123456789",
        "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~"
    }
    repeat
        index = index + 1
        rnd = math.random(chars[index]:len())
        if math.random(2) == 1 then
            pw = pw .. chars[index]:sub(rnd, rnd)
        else
            pw = chars[index]:sub(rnd, rnd) .. pw
        end
        index = index % #chars
    until pw:len() >= length
    return pw
end

math.randomseed(os.time())
if #arg ~= 2 then
    print("\npwgen.lua")
    print("=========\n")
    print("A Lua script to generate random passwords.\n")
    print("Usage:    lua pwgen.lua [password length] [number of passwords to generate]\n")
    os.exit()
end
for i = 1, arg[2] do print(randPW(tonumber(arg[1]))) end

Command line session:

>lua pwgen.lua

pwgen.lua
=========

A Lua script to generate random passwords.

Usage:  lua pwgen.lua [password length] [number of passwords to generate]


>lua pwgen.lua 8 4
!A%1Ghs5
)cU?2eT5
9wHh1'V/
6lN9*Nx<

M2000 Interpreter

Using COMMODORE's BASIC

Although M2000 has OOP, lambda functions as a modern language,can operate like BASIC. Here there a Commodore Basic program converted for M2000. Also we set 40X25 character mode.

The For Next for M2000 works every timem so For i=1 to 0: print i: next i execute twice. So to make it like BASIC we have to use an if before to skip For. There is a special switch for M2000 Interpreter to set For loop exactly like basic. Gere we don't have a case which skip the for loop. So I leave it as is. The problem from Commodore Basic was a Goto 110 on line 145. This goto do an exit from For loop. So ffor M2000 this has to be Exit For 100 (which reqind an internal stack for for loops and then do the loop). M2000 has another for loop using curly braces, and there we can use goto to jumn out of loop without exit for statement.

MODULE PASSWORD_CREATOR {
	1 rem password generator
	2 rem rosetta code
	3 dim g$(1 to 4), pw$(1 to 10), g(1 to 10)
	4 def tab(x)=string$(" ", max.data(pos, x-1)-pos)
	5 def rnd(x)=rnd*x
	6 rem from COMMODORE BASIC
 	7 Form 40, 25	 
	10 g$(1)="abcdefghijklmnopqrstuvwxyz"
	15 g$(2)="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	20 g$(3)="0123456789"
	25 g$(4)="<>!@#$%^&*()[];:'.?/"
	30 CLS ' print chr$(147);chr$(14)
	35 print "Password Generator":print
	40 print "Press H for help, or any":print "other key to begin.":print
	45 k$=inkey$:if k$="" then 45
	50 if k$="h" or k$="H" then gosub 500
	60 CLS ' print chr$(147)
	65 input "Enter password length: (6-30):";pl
	70 if pl<6 or pl>30 then print "Out of range.":goto 65
	75 print:input "How many passwords (1-20):";np
	80 if np<1 or np>20 then print "Out of range.":goto 75
	85 if np>10 then dim pw$(1 to np)
	90 if np*pl > 100 then print:print "Um... Ok, this might take a bit."
	100 for pc=1 to np
	105   for i=1 to 4:g(i)=0:next
	110   tp$=""
	112   for i=1 to pl
	115     cg=int(rnd(1)*4)+1
	120     cc=int(rnd(1)*len(g$(cg)))+1
	125     tp$=tp$+mid$(g$(cg),cc,1)
	130     g(cg)=g(cg)+1
	135   next i
	140   for i=1 to 4
	145     if g(i)=0 then exit for 110
	150   next i
	155   pw$(pc)=tp$
	160 next pc
	200 CLS: print "Password list:":print
	205 for pc=1 to np:print pc;".";tab(6);pw$(pc):next pc
	210 print:print "Again? (y/n)";
	215 k$=inkey$:if k$<>"y" and k$<>"n" and k$<>"Y" and k$<>"N" then 215
	220 if k$="y" or k$="Y" then clear:goto 1
	225 end
	500 rem *** help ***
	505 CLS: print "This program will generate a password"
	510 print "made up of each of the following"
	515 print "character types:":print
	520 print " - Uppercase Letter (A-Z)"
	525 print " - Lowercase Letter (a-z)"
	530 print " - Number (0-9)"
	535 print " - Punctuation and Other Symbols"
	540 print "   (e.g. # $ ! & [ . ;, etc.)"
	545 print
	550 print "You may choose how many total characters";
	555 print "(up to 30) should be in the password, "
	560 print "and how many passwords (up to 20) should";
	565 print "be generated. The program ensures that "
	570 print "there is at least one character from "
	575 print "each of the character types in each "
	580 print "password."
	585 print
	590 print "Note: You can edit the character lists"
	595 print "on lines 10-25 to customize the"
	600 print "selection pool."
	605 print
	610 print "Press any key to begin."
	615 k$=inkey$:if k$="" then 615
	620 return
}
PASSWORD_CREATOR

Output same as Commodore Basic

Using Modules

We use drop down menu to choose safe/unsafe, and to choose one of the many passwords to copy it to clipboard.

module SetUp{
	form 80, 50
	print "Password Generator"
	
	input "Set seed (press enter without number to skip):"; seed$
	seed$=trim$(seed$)
	' we always push a new seed - there is a two stage queue
	if len(seed$)>0 then
		x=random(!val(seed$))
	else
		x=random(!timecount)
	end if
	def zone(x, a, b) = x >=a and x<=b
	do
		Input "Length for password (6 to 30), Number of passwords (1 to 20):", a%, b%
	until zone(a%, 6, 30) and zone(b%, 1, 20)
	print "choose mode:";
	menu "safe", "unsafe"
	unsafe= menu=2
	if unsafe then print "unsafe" else print "safe"
	menu ' clear menu
	flush
	data not unsafe, a%, b%
}
module pass (safe as  boolean, a1 as integer, b1 as integer) {
	dim a(0 to 4) as string,  b(1 to 4) as boolean
	if safe then
		a(1) := "346789",  "ABCDEFGHJKLMNPQRTUVWXY", "abcdefghijkmnopqrstuvwxyz"
	else
		a(1) := "0123456789", "ABCDEFGHIJKLMNOPQRSTUVWXYZ",  "abcdefghijklmnopqrstuvwxyz" 
	end if
	a(4) = "!" + """" + "#$%&'()*+,-./:;<=>?@[]^_{|}~"
	a(0)= a(1) + a(2) + a(3) + a(4)
	string s, d
	integer k=1
	while b1
		do
			s=""
			for j=1 to 4:	b(j)=false:next
			for i=1 to a1
				s+=mid$((a(0)), random(1, len(a(0))), 1)
				for j=1 to 4
					if  instr(a(j), d)>0 then b(j)=true
				next
			next
		until b(1) and b(2) and b(3) and b(4)    
		menu + format$("{0::-2}. {1}", k, s)
		b1--
		k++
	end while
	x=random(!) ' pop the old seed back
}
module copy2clipboard {
	if menuitems>0 then
		print "choose one:";
		menu !
		if menu>0 then
			m=menu
		else
			m=1
		end if
		print mid$(menu$(m), 5)
		try {	
			clipboard mid$(menu$(m), 5)
			print "clipboard set"
		}
	end if
}
' now we call the three parts - modules
setup
pass       ' paraneters are in stack of values
copy2clipboard

Mathematica /Wolfram Language

(* Length is the Length of the password, num is the number you want, \
and similar=1 if you want similar characters, 0 if not. True and \
False, should work in place of 1/0 *)
pwgen[length_Integer: 5, num_Integer: 1, similars_Boolean: 1] := 
 pwgenerator[length, num, similars] = 
  Module[{list, valid, validchars, similar, k, j, password, pwlist, 
    lcase, ucase, digits, spec, s}, lcase = Alphabet[];
   ucase = Capitalize[lcase];
   digits = Range[0, 9];
   spec = StringPartition["!:#$%\'()*+,-./:;>=<?@{}[]^_|~", 1];
   validchars = Flatten[Union[lcase, ucase, digits, spec]];
   similar = StringPartition["Il10O5S2Z", 1];
   list = {};
   
   Table[valid = 0;
    While[valid == 0,
     For[j = 0; k = {};, j < length, j++, 
      AppendTo[k, RandomInteger[{1, Length[validchars]}]]];
     k = Flatten[k];
     password = validchars[[k]];
     Which[(Intersection[password, similar] >= 1 && similars == 0 ), 
      valid = 0;, (Intersection[password, similar] == 0 && 
        similars == 1), 
      valid = 0;, (Intersection[password, similar] == 0 && 
        similars == 0 ), valid = 1; 
      Return[password], (Intersection[password, similar] >= 1 && 
        similars == 1), valid = 1; Return[password]];
     ], {num}];
   
   
   ]

Nim

import os, parseopt, random, sequtils, strformat, strutils

const Symbols = toSeq("!\"#$%&'()*+,-./:;<=>?@[]^_{|}~")


proc passGen(passLength = 10,
             count = 1,
             seed = 0,
             excludeSimilars = false): seq[string] =
  ## Generate a sequence of passwords.

  # Initialize the random number generator.
  if seed == 0: randomize()
  else: randomize(seed)

  # Prepare list of chars per category.
  var
    lowerLetters = toSeq('a'..'z')
    upperLetters = toSeq('A'..'Z')
    digits = toSeq('0'..'9')

  if excludeSimilars:
    lowerLetters.delete(lowerLetters.find('l'))
    for c in "IOSZ": upperLetters.delete(upperLetters.find(c))
    for c in "012": digits.delete(digits.find(c))

  let all = lowerLetters & upperLetters & digits & Symbols

  # Generate the passwords.
  for _ in 1..count:
    var password = newString(passLength)
    password[0] = lowerLetters.sample
    password[1] = upperLetters.sample
    password[2] = digits.sample
    password[3] = Symbols.sample
    for i in 4..<passLength:
      password[i] = all.sample
    password.shuffle()
    result.add password


proc printHelp() =
  ## Print the help message.
  echo &"Usage: {getAppFileName().lastPathPart} " &
        "[-h] [-l:length] [-c:count] [-s:seed] [-x:(true|false)]"
  echo "  -h: display this help"
  echo "  -l: length of generated passwords"
  echo "  -c: number of passwords to generate"
  echo "  -s: seed for the random number generator"
  echo "  -x: exclude similar characters"


proc getIntValue(key, val: string): int =
  ## Get a positive integer value from a string.
  try:
    result = val.parseInt()
    if result <= 0:
      raise newException(ValueError, "")
  except ValueError:
    quit &"Wrong value for option -{key}: {val}", QuitFailure


var
  passLength = 10
  count = 1
  seed = 0
  excludeSimilars = false

# Process options.
var parser = initOptParser()

for kind, key, val in parser.getopt():
  if kind != cmdShortOption:
    printHelp()
    quit(QuitFailure)

  case key
  of "h":
    printHelp()
    quit(QuitSuccess)
  of "l":
    passLength = getIntValue(key, val)
  of "c":
    count = getIntValue(key, val)
  of "s":
    seed = getIntValue(key, val)
  of "x":
    if val.toLowerAscii == "true":
      excludeSimilars = true
    elif val.toLowerAscii == "false":
      excludeSimilars = false
    else:
      quit &"Wrong value for option -x: {val}", QuitFailure
  else:
    quit &"Wrong option: -{key}"

# Display the passwords.
for pw in passGen(passLength, count, seed, excludeSimilars):
  echo pw
Output:
$ ./passgen -c:6
hG']0ipc7P
1|"AjJDYxe
VwU'!7<+!<
=Do]49_vd5
4lqrr>B*X1
8J1_J#>hi7

OCaml

let lower = "abcdefghijklmnopqrstuvwxyz"
let upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
let digit = "0123456789"
let other = "!\034#$%&'()*+,-./:;<=>?@[]^_{|}~"

let visually_similar = "Il1O05S2Z"


let mk_pwd len readable =
  let get_char i =
    match i mod 4 with
    | 0 -> lower.[Random.int (String.length lower)]
    | 1 -> upper.[Random.int (String.length upper)]
    | 2 -> digit.[Random.int (String.length digit)]
    | 3 -> other.[Random.int (String.length other)]
    | _ -> raise Exit
  in
  let f =
    if readable then
      (fun i ->
        let rec aux () =
          let c = get_char i in
          if String.contains visually_similar c
          then aux ()
          else (String.make 1 c)
        in
        aux ()
      )
    else
      (fun i ->
        let c = get_char i in
        (String.make 1 c)
      )
  in
  let r = Array.init len f in
  Array.sort (fun _ _ -> (Random.int 3) - 1) r;
  (String.concat "" (Array.to_list r))


let () =
  Random.self_init ();
  let num = ref 1 in
  let len = ref 8 in
  let readable = ref false in
  let speclist = [
    "-n", Arg.Set_int num, "number of passwords";
    "-c", Arg.Set_int len, "number of characters";
    "--readable", Arg.Set readable, "readable";
    "--rand-init", Arg.String (fun s ->
        Random.full_init 
          (Array.map int_of_char (Array.of_seq (String.to_seq s)))
      ), "initialise the random generator with a string";
  ] in
  Arg.parse speclist (fun s -> invalid_arg s) "Password generator";
  for i = 1 to !num do
    print_endline (mk_pwd !len !readable)
  done
Output:
$ ocaml mkpwd.ml --help
Password generator
  -n number of passwords
  -c number of characters
  --readable readable
  --rand-init initialise the random generator with a string
  --help  Display this list of options

$ ocaml mkpwd.ml 
Zz&tJ[40

$ ocaml mkpwd.ml -n 3 -c 16 --readable --rand-init rosettacode.org
_6yAXM(o4+Gw~73p
]]Pf}84"bwKUH84b
.TijWj7~743Q<K;q

ooRexx

Translation of: [[#|]] – REXX
/*REXX program generates a  random password  according to the Rosetta Code task's rules.*/
parse arg L N seed xxx dbg                       /*obtain optional arguments from the CL*/
casl= 'abcdefghijklmnopqrstuvwxyz'               /*define lowercase alphabet.           */
casu= translate(casle)                           /*define uppercase alphabet.           */
digs= '0123456789'                               /*define digits.                       */
/* avoiding the ambiguous characters Il1 o0 5S                                          */
casl= 'abcdefghijkmnpqrtuvwxy'                   /*define lowercase alphabet.           */
casu= translate(casl)                            /*define uppercase alphabet.           */
digs= '0123456789'                               /*define digits.                       */
spec= '''!"#$%&()+,-./:;<=>?@[]^{|}~'            /*define a bunch of special characters.*/
if L='?'               then call help            /*does user want documentation shown?  */
if L=''  | L=","       then L=8                  /*Not specified?  Then use the default.*/
If N=''  | N=","       then N=1                  /* "      "         "   "   "     "    */
If xxx=''| xxx=","     then xxx='1lI0O2Z5S'      /* "      "         "   "   "     "    */
if seed>'' &,
   seed<>','            then Do
  if \datatype(seed,'W')then call ser "seed is not an integer:" seed
  Call random ,,seed                             /*the seed for repeatable RANDOM BIF #s*/
  End
casl=remove(xxx,casl)
casu=remove(xxx,casu)
digs=remove(xxx,digs)
Say 'casl='casl
Say 'casu='casu
Say 'digs='digs
Say 'spec='spec
if \datatype(L,   'W')  then call ser "password length, it isn't an integer: "       L
if L<4                  then call ser "password length, it's too small: "            L
if L>80                 then call ser "password length, it's too large: "            L
if \datatype(N,   'W')  then call ser "number of passwords, it isn't an integer: "   N
if N<0                  then call ser "number of passwords, it's too small: "        N

    do g=1  for N                                /*generate  N  passwords (default is 1)*/
    pw=letterL()||letterU()||numeral()||special()/*generate  4  random  PW constituents.*/
            do k=5  to  L;       z=random(1, 4)  /* [?]  flush out PW with more parts.  */
            if z==1  then pw=pw || letterL()     /*maybe append random lowercase letter.*/
            if z==2  then pw=pw || letterU()     /*  "      "      "   uppercase    "   */
            if z==3  then pw=pw || numeral()     /*  "      "      "       numeral      */
            if z==4  then pw=pw || special()     /*  "      "      "   special character*/
            end   /*k*/                          /* [?]  code below randomizes PW chars.*/
    t=length(pw)                                 /*the length of the password (in bytes)*/
            do L+L                               /*perform a random number of char swaps*/
            a=random(1,t);     x=substr(pw,a,1)  /*A: 1st char location;  X is the char.*/
            b=random(1,t);     y=substr(pw,b,1)  /*B: 2nd   "      "      Y  "  "    "  */
            pw=overlay(x,pw,b);  pw=overlay(y,pw,a)  /* swap the two chars.             */
            end  /*swaps*/                       /* [?]  perform extra swap to be sure. */
    say right(g,length(N))  'password is: ' pw counts() /*display the  Nth  password    */
    end       /*g*/
exit                                             /*stick a fork in it,  we're all done. */
/*--------------------------------------------------------------------------------------*/
ser:      say;   say '***error*** invalid' arg(1);  exit 13   /*display an error message*/
letterL:  return substr(casl, random(1, length(casl)), 1)   /*return random lowercase.*/
letterU:  return substr(casu, random(1, length(casu)), 1)   /*   "      "   uppercase.*/
numeral:  return substr(digs, random(1, length(digs)), 1)   /*   "      "    numeral. */
special:  return substr(spec, random(1, length(spec)), 1)   /*   "      " special char*/
remove: Procedure
  Parse arg nono,s
  Return space(translate(s,'',nono),0)
/*--------------------------------------------------------------------------------------*/
counts:
  If dbg>'' Then Do
    cnt.=0
    str.=''
    Do j=1 To length(pw)
      c=substr(pw,j,1)
      If pos(c,casL)>0 Then Do; cnt.0casL=cnt.0casL+1; str.0casL=str.0casL||c; End
      If pos(c,casU)>0 Then Do; cnt.0casU=cnt.0casU+1; str.0casU=str.0casU||c; End
      If pos(c,digs)>0 Then Do; cnt.0digs=cnt.0digs+1; str.0digs=str.0digs||c; End
      If pos(c,spec)>0 Then Do; cnt.0spec=cnt.0spec+1; str.0spec=str.0spec||c; End
      End
    txt=cnt.0casL cnt.0casU cnt.0digs cnt.0spec
    If pos(' 0 ',txt)>0 Then
      txt=txt 'error'
    Return txt str.0casL str.0casU str.0digs str.0spec
    End
  Else
    txt=''
  Return txt
help:     signal .; .:   do j=sigL+2  to sourceline()-1; say sourceline(j); end;    exit 0
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~ documentation begins on next line.~~~~~~~~~~~~~~~~~~~~~~~~~
+-----------------------------------------------------------------------------+
¦ Documentation for the  GENPW  program:                                      ¦
¦                                                                             ¦
¦ Rexx genpwd <length|,> <howmany|,> <seed|,> <xxx|,>     <dbg>               ¦
¦                     8           1     n     '1lI0O2Z5S'  none    Defaults   ¦
¦                                                                             ¦
¦--- where:                                                                   ¦
¦           length      is the length of the passwords to be generated.       ¦
¦                       The default is  8.                                    ¦
¦                       If a  comma (,)  is specified, the default is used.   ¦
¦                       The minimum is  4,   the maximum is  80.              ¦
¦                                                                             ¦
¦           howMany     is the number of passwords to be generated.           ¦
¦                       The default is  1.                                    ¦
¦           xxx         Characters NOT to be used in generated passwords      ¦
¦           dbg         Schow count of characters in the 4 groups             ¦
+-----------------------------------------------------------------------------+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~documentation ends on the previous line.~~~~~~~~~~~~~~~~~~~*/
Output:
D:\>rexx genpwd 12 4 33 , x
casl=abcdefghijkmnpqrtuvwxy
casu=ABCDEFGHJKMNPQRTUVWXY
digs=346789
spec='!"#$%&()+,-./:;<=>?@[]^{|}~
1 password is:  B78<3(3Et(U8 1 3 5 3 t BEU 78338 <((
2 password is:  v+k6X6AV^;[7 2 3 3 4 vk XAV 667 +^;[
3 password is:  x3MV:7?CcH{D 2 5 2 3 xc MVCHD 37 :?{
4 password is:  C49PHCj[~D9/ 1 5 3 3 j CPHCD 499 [~/

D:\>regina genpwd 12 4 33 , x
casl=abcdefghijkmnpqrtuvwxy
casu=ABCDEFGHJKMNPQRTUVWXY
digs=346789
spec='!"#$%&()+,-./:;<=>?@[]^{|}~
1 password is:  e4)XnD4jq"xb 6 2 2 2 enjqxb XD 44 )"
2 password is:  9r3H:a97HyW8 3 3 5 1 ray HHW 93978 :
3 password is:  y76-^r^M{8JQ 2 3 3 4 yr MJQ 768 -^^{
4 password is:  C$W@aMHBjc8g 4 5 1 2 ajcg CWMHB 8 $@ 

PARI/GP

PARI/GP has a very good builtin random generator.

passwd(len=8, count=1, seed=0) =
{
  if (len <= 4, print("password too short, minimum len=4"); return(), seed, setrand(seed));

  my (C=["abcdefghijklmnopqrstuvwxyz","ABCDEFGHIJKLMNOPQRSTUVWXYZ","0123456789","!\"#$%&'()*+,-./:;<=>?@[]^_{|}~"], P, j);

  for (i=1, count, K = vector(#C); P = "";
    for (l=1, len, K[j = random(#C)+1]++;
      P = concat(P, Strchr(Vecsmall(C[j])[random(#C[j])+1]))
    );
    if (prod(z=1, #K, K[z]), print(P), i--)    \\ if password contains all char classes print else redo  
  );
}

addhelp(passwd, "passwd({len},{count},{seed}): Password generator, optional: len (min=4, default=8), count (default=1), seed (default=0: no seed)");

Output: passwd()

34K76+mB

Output of 10 passwords of length 8 with seed enabled: passwd(8,10,1)

6,89DhJa
xO<XsR8b
R&UagR5h
*21e((D%
pR5Ss&rW
7o7]Fuj+
:N6C6y2L
$L?1s4x)
1R5q'5pw
#4vmVHy5

Show help: ?passwd

passwd({len},{count},{seed}): Password generator, optional: len (min=4, default=8), count (default=1), seed (default=0: no seed)

Pascal

program passwords (input,output);

{$mode objfpc}
{$H+} { We will need ansi strings instead of short strings
        to hold passwords longer than 255 characters.
        We need to assemble a string to check that each
        password contains an upper, lower, numeral and symbol }

{ This is a random password generater in PASCAL
  Copyright Englebert Finklestien on this day which is
  Setting Orange day 48 of The Aftermath YOLD 3184.
  It is distributed under the terms of the GNU GPL (v3)
  As published by the free software foundation.

  Usage :-
  Without any command line arguments this program
  will display 8 8-character long completely random passwords using
  all 96 available character glyphs from the basic ascii set.

  With a single integer numerical argument it will
  produce eight passwords of the chosen length.

  With a second integer numerical argument between 1 and 65536 it
  will produce that number of passwords.

  With two integer arguments the first is taken as the length of password
  and the second as the number of passwords to produce.

  The length of passwords can also be specified using -l or --length options

  The number of passwords can also be specified using -n or --number options

  It is also possible to exclude those glyphs which are simmilar enough to be
  confused (e.g. O and 0) using the -e or --exclude option

  There are also the standard -a --about and -h --help options

  Other options will produce an error message and the program will halt without
  producing any passwords at all.

 }

uses sysutils, getopts;



var c : char;
    optionindex : Longint;
    theopts : array[1..5] of TOption;
    numpass, lenpass, count,j : integer;
    i : longint; { used to get a random number }
    strength : byte; {  check inclusion of different character groups }
    password : string; { To hold a password as we generate it }
    exc : boolean;
    ex : set of char;

procedure about;
begin
     writeln('Engleberts random password generator');
     writeln('Writen in FreePascal on Linux');
     writeln('This is free software distributed under the GNU GPL v3');
     writeln;
end;

procedure help;
begin
    writeln('Useage:-');
    writeln('passwords   produce 8 passwords each 8 characters long.');
    writeln('Use one or more of the following switches to control the output.');
    writeln('passwords --number=xx -nxx --length=xx -lxx --exclude -e --about -a --help -h');
    writeln('passwords ll nn produce nn passwords of length ll');
    writeln('The exclude option excludes easily confused characters such as `0` and `O` from');
    writeln('the generated passwords.');
    writeln;
end;


begin
  numpass := 8;
  lenpass := 8;
  exc := False;
  ex := ['1','!','l','|','i','I','J','0','O','S','$','5',';',':',',','.','\']; { Set of ambiguous characters }
  OptErr := True;
  Randomize;  {initialise the random number generator}
  {set up to handle the command line options}
  with theopts[1] do
   begin
    name:='length';
    has_arg:=1;
    flag:=nil;
    value:=#0;
   end;
  with theopts[2] do
   begin
    name:='number';
    has_arg:=1;
    flag:=nil;
    value:=#0;
   end;
  with theopts[3] do
   begin
    name:='help';
    has_arg:=0;
    flag:=nil;
    value:=#0;
   end;
  with theopts[4] do
   begin
    name:='about';
    has_arg:=0;
    flag:=nil;
    value:=#0;
   end;
  with theopts[5] do
   begin
    name:='exclude';
    has_arg:=0;
    flag:=nil;
    value:=#0;
   end;

{ Get and process long and short versions of command line args. }
  c:=#0;
  repeat
    c:=getlongopts('ahel:n:t:',@theopts[1],optionindex);
    case c of
      #0 : begin
               if (theopts[optionindex].name = 'exclude') then exc := True;
               if (theopts[optionindex].name = 'length') then lenpass := StrtoInt(optarg);
               if (theopts[optionindex].name = 'number') then numpass := StrtoInt(optarg);
	       if (theopts[optionindex].name = 'about') then about;
	       if (theopts[optionindex].name = 'help') then help;
           end;
      'a' : about;
      'h' : help;
      'e' : exc := True;
      'l' : lenpass := StrtoInt(optarg);
      'n' : numpass := StrtoInt(optarg);
      '?',':' : writeln ('Error with opt : ',optopt);
    end; { case }
  until c=endofoptions;
  { deal with any remaining command line parameters (two integers)}
  if optind<=paramcount then
    begin
       count:=1;
       while optind<=paramcount do
         begin
	    if (count=1) then lenpass := StrtoInt(paramstr(optind)) else numpass := StrtoInt(paramstr(optind));
            inc(optind);
	    inc(count);
         end;
    end;
	if not (exc) then ex :=['\']; { if we are not going to exclude characters set the exclusion set to almost empty }
	{ This generates and displays the actual passwords  }
    for count := 1 to numpass do begin
       strength := $00;
       repeat
          password :='';
          for j:= 1 to lenpass do begin
             repeat
                i:=Random(130);
             until (i>32) and (i<127) and (not(chr(i) in ex)) ;
             AppendStr(password,chr(i));
             if (CHR(i) in ['0'..'9']) then strength := strength or $01;
             if (chr(i) in ['a'..'z']) then strength := strength or $02;
             if (chr(i) in ['A'..'Z']) then strength := strength or $04;
             if (chr(i) in ['!'..'/']) then strength := strength or $08;
             if (chr(i) in [':'..'@']) then strength := strength or $08;
             if (chr(i) in ['['..'`']) then strength := strength or $08;
             if (chr(i) in ['{'..'~']) then strength := strength or $08;
         end;	 
       until strength = $0f;
    writeln(password);
    end;
end.

Useage for the output example: passwords --about -h --length=12 --number 12 --exclude

Output:

Engleberts random password generator
Writen in FreePascal on Linux
This is free software distributed under the GNU GPL v3

Useage:-
passwords   produce 8 passwords each 8 characters long.
Use one or more of the following switches to control the output.
passwords --number=xx -nxx --length=xx -lxx --exclude -e --about -a --help -h
passwords ll nn produce nn passwords of length ll
The exclude option excludes easily confused characters such as `0` and `O` from
the generated passwords.

G6ZnfCMoR8)8
]V-Y"L8tFPYM
gveA]%2onN)g
j?4Rz)C(x?RY
mQ]2c)RP~dvU
8<GT{w)]>w^t
Fw"^~73zY8`"
d4KGQmTB4#Nn
PwqYLMEpegv3
mbe^NCTF'a~t
g@vc"B{X+9kg
4tD3w?Vgo_R@

using FreePascal

Works with: Free Pascal version 3.2.2
PROGRAM pwgen;

(*)

		Free Pascal Compiler version 3.2.2 [2024/05/01] for x86_64
		
		Free to use, as is, experimental , different take on the parameter boilerplate stuff..

		directives:
		https://www.freepascal.org/docs-html/prog/progch1.html

        The free and readable alternative at C/C++ speeds
        compiles natively to almost any platform, including raspberry PI *
        Can run independently from DELPHI / Lazarus

        https://www.freepascal.org/advantage.var
        
(*)


{$IFDEF FPC}
	{$mode objfpc}          (*) directive to be used for defining classes   (*)

	{$LONGSTRINGS ON}       (*) aka {H+}  = ansistrings                     (*)
	{$RANGECHECKS ON}       (*) aka {$R+}                                   (*)
	{$S+}                   (*) stack checking on                           (*)
	{$TYPEDADDRESS ON}      (*) aka {$T+}                                   (*)
{$ELSE}
	{$APPTYPE CONSOLE}
{$ENDIF}

{$MACRO ON}
{$DEFINE crlf   := #13#10 }
{$DEFINE tab    := #9     }
{$DEFINE quot   := #39	  }
{$DEFINE dquot  := #34    }
{$WARN 6058 off : Call to subroutine "$1" marked as inline is not inlined} // Use for variants, complex numbers

USES

	crt,
	Math,
	SysUtils,
	TypeUtils
	;
	
TYPE

	List  	  = array of string ;

// Mod to change printing behaviour of plural
OPERATOR * (const A: char; const B: boolean): char;
	BEGIN	IF B = True THEN Result := A  ;	END;


// Oneline if-then-else
FUNCTION IIF ( Cond: boolean;  A, B: variant ) : variant ;
	BEGIN	IF ( Cond ) THEN IIF := A ELSE IIF := B ;	END ;

	
// Mod to change behaviour, needed in GetPVal
OPERATOR IN (const A: string; const B: string): integer;  
	BEGIN	Result := pos( A, B ) ;	END;

// Mod for options
FUNCTION GetPVal ( parm:string; opt:string): integer;

	BEGIN
	
		GetPVal := opt in parm;
		
		IF  GetPVal > 0 THEN
		  GetPVal:= ( StrToIntDef( Copy( parm, Min( High( parm ), GetPVal + 2 ) ).Split(' ')[0], 0 ));
	END;



FUNCTION PickFrom ( S: string ): char;
	BEGIN	PickFrom := S[ math.RandomRange( Low(S), high(S) ) ] ;	END;



(*) MAINLINE (*)

VAR
	L:			  List ;
	_:			string ;
	S:			string ;
	excluding : array of char = ( '|','I','l','1','O','0','5','S','Z','2' ) ;
	numb3rs:	string = '0123456789';
	l3tters:	string = 'abcdefghijklmnopqrstuvwxyz';
	speci4ls:	string = '!"#$%&''()*+,-./:;<=>?@[]^_{|}~';
	j,k:		integer;
	n:			integer =  1;
	w:			integer = 17;
	parm:		string  = '';

BEGIN
	Randomize;

	FOR k := 1 TO paramcount() DO
		parm := parm + paramstr( k ) + ' ' ;

	IF '-h' IN parm > 0 THEN
		BEGIN
		  WriteLn	(  crlf , 'pwgen -[hwren]',		  crlf ) ;
		  WriteLn ( 'Generates random passwords.' , crlf , 'Without options it generates ', n ,' password',  's' * (n > 1),', of width ', w , '.',	crlf ) ;
		  WriteLn ( 'options: -h(elp), -w(idth of password [ 8 to 500 ] ), -r(andom seed), -e(xlude lookalikes), -n(r of passwords [ 1 to 500 ])',  	crlf ) ;
		  WriteLn ( 'ex. :  ./pwgen -n7 -w15 -r17', crlf ) ;
		  Exit();
		END; // IF '-h' IN parm

	n 		  :=  IIF ( GetPVal ( parm, '-n') = 0, 		n,  Min ( 500, Max ( GetPVal ( parm, '-n'), 1) ) ) ;
	w 		  :=  IIF ( GetPVal ( parm, '-w') = 0, 		w,	Min ( 500, Max ( GetPVal ( parm, '-w'), 8) ) ) ;
	RandSeed  :=  IIF ( GetPVal ( parm, '-r') = 0, RandSeed,	GetPVal ( parm, '-r') ) ;

	FOR j := 1 TO n DO

	  BEGIN

		S:='';

		FOR k := 0 TO w DO
		  S := S + PickFrom( numb3rs ) + PickFrom( l3tters ) + PickFrom( speci4ls ) + PickFrom( UpperCase( l3tters ) );

		IF '-e' IN parm > 0 THEN

			BEGIN
					
			    L := S.Split( excluding) ;
					
				FOR _ in L DO
				    S := S + _ ;

			END; // IF '-e' IN parm

			WriteLn( copy( S, math.RandomRange ( Low( S ), High( S ) - w ), w ) );

	END; // FOR j := 1
	
END. (*) Of PROGRAM pwgen.pas (*)

(*)
JPD 2024/10/26 https://rosettacode.org/wiki/Password_generator#Pascal 

./pwgen -n7 -w15 -r17

Output:

K6y,O1v_P7h$Q4o
S8w^L1y=Q1u[K6e
C2t/L5l{V5i_E8t
w&U6h'M5c&Q5h|R
^J2o!W6a_S5c(U8
4e|I3e@Q7k:R3d]
w}F5l,V8u(V4b*Q


(*)

Perl

Use the module Math::Random for marginally better random-ness than the built-in function, but no warranty is expressed or implied, caveat emptor.

use strict;
use warnings;
use feature 'say';

use English;
use Const::Fast;
use Getopt::Long;
use Math::Random;

const my @lcs    => 'a' .. 'z';
const my @ucs    => 'A' .. 'Z';
const my @digits => 0 .. 9;
const my $others => q{!"#$%&'()*+,-./:;<=>?@[]^_{|}~};  # "

my $pwd_length  = 8;
my $num_pwds    = 6;
my $seed_phrase = 'TOO MANY SECRETS';

my %opts = (
'password_length=i' => \$pwd_length,
'num_passwords=i'   => \$num_pwds,
'seed_phrase=s'     => \$seed_phrase,
'help!'             => sub {command_line_help(); exit 0}
);
command_line_help() and exit 1 unless $num_pwds >= 1 and $pwd_length >= 4 and GetOptions(%opts);

random_set_seed_from_phrase($seed_phrase);
say gen_password() for 1 .. $num_pwds;

sub gen_password {
    my @generators = (\&random_lc, \&random_uc, \&random_digit, \&random_other);
    my @chars = map {$ARG->()} @generators;  # At least one char of each type.
    push @chars, $generators[random_uniform_integer(1, 0, 3)]->() for 1 .. $pwd_length - 4;
    join '', random_permutation(@chars);
}

sub random_lc    {    $lcs[ random_uniform_integer(1, 0, $#lcs)    ] }
sub random_uc    {    $ucs[ random_uniform_integer(1, 0, $#ucs)    ] }
sub random_digit { $digits[ random_uniform_integer(1, 0, $#digits) ] }
sub random_other { substr($others, random_uniform_integer(1, 0, length($others)-1), 1) }

sub command_line_help {
    say <<~END
       Usage: $PROGRAM_NAME
       [--password_length=<l> default: 8, minimum: 4]
       [--num_passwords=<n>   default: 6, minimum: 1]
       [--seed_phrase=<s>     default: TOO MANY SECRETS (optional)]
       [--help]
       END
}
Output:
sc3O~3e0
pE{uh7)%
3J:'L)x8
I{A:h454
tCTH}8(h
b0&S$ZtI

Phix

--with javascript_semantics -- not quite yet:
without js -- (VALUECHANGED_CB not yet triggering)
constant az = "abcdefghijklmnopqrstuvwxyz",
         AZ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
         O9 = "1234567890",
         OT = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~"
 
function password(integer len, integer n, sequence exclude="Il1O05S2Z")
    sequence res = {},
             S4 = apply(true,filter,{{az,AZ,O9,OT},{"out"},{exclude}})
    string pw = repeat(' ',len)
    for i=1 to n do
        sequence sel = shuffle({1,2,3,4}&sq_rand(repeat(4,len-4)))
        for c=1 to len do
            string S4c = S4[sel[c]]
            pw[c] = S4c[rand(length(S4c))]
        end for
        res = append(res,pw)
    end for
    return res
end function

include pGUI.e

Ihandle lenl, leng, numl, numb, res, dlg

function valuechanged_cb(Ihandle /*leng|numb*/)
    integer l = IupGetInt(leng,"VALUE"),
            n = IupGetInt(numb,"VALUE")
    string s = join(password(l,n),"\n")
    s = substitute(s,"&","&&") -- (on p2js??)
    IupSetStrAttribute(res,"TITLE",s)
    IupSetAttribute(dlg,"SIZE",NULL)
    IupRefresh(dlg)
    return IUP_DEFAULT
end function

procedure main()
    IupOpen()
    lenl = IupLabel("length(4..99)")
    leng = IupText("SPIN=YES,SPINMIN=4,SPINMAX=99")
    numl = IupLabel("number(1..99)")
    numb = IupText("SPIN=YES,SPINMIN=1,SPINMAX=99")
    res = IupLabel("","FONTFACE=Courier")
    IupSetCallback({leng,numb},"VALUECHANGED_CB", Icallback("valuechanged_cb"))
    dlg = IupDialog(IupVbox({IupHbox({lenl,leng,numl,numb},"GAP=10,NORMALIZESIZE=VERTICAL"),
                             IupHbox({res})},"MARGIN=5x5"),
                            `TITLE="Password Generator"`)
    IupShow(dlg)
    if platform()!=JS then
        IupMainLoop()
        IupClose()
    end if
end procedure
 
main()
Output:

With a length of 12 and generating 6 of them

:EtF77s~%bok
C^Pb&NH8@?u6
RBy%Ep*N9W!t
K%6hxc?C_4_3
vpRBJP)A9@,7
V_3dDf7RhY7N

PicoLisp

#!/usr/bin/pil

# Default seed
(seed (in "/dev/urandom" (rd 8)))

# Global defaults
(setq
   *PwCount 1
   *PwLength 12
   *UppChars (mapcar char (range (char "A") (char "Z")))
   *LowChars (mapcar lowc *UppChars)
   *Digits (mapcar format (range 0 9))
   *Others (chop "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~") )

# Command line options
(de -count ()
   (setq *PwCount (format (opt))) )

(de -length ()
   (setq *PwLength (format (opt))) )

(de -seed ()
   (seed (opt)) )

(de -exclude ()
   (for C (chop (opt))
      (del C '*UppChars)
      (del C '*LowChars)
      (del C '*Digits)
      (del C '*Others) ) )

(de -help ()
   (prinl "Generate password(s)")
   (prinl "Options:")
   (prinl "   --help")
   (prinl "   --count <num>")
   (prinl "   --length <num>")
   (prinl "   --seed <chars>")
   (prinl "   --exclude <chars>")
   (bye) )

(load T)

# Return random character from list
(de randChar (Lst)
   (get Lst (rand 1 (length Lst))) )

# Generate password(s)
(do *PwCount
   (prinl
      (by '(NIL (rand)) sort
         (make
            (link
               (randChar *UppChars)  # At least one from each group
               (randChar *LowChars)
               (randChar *Digits)
               (randChar *Others) )
            (do (- *PwLength 4)
               (link
                  (randChar
                     (caar
                        (rot '(*UppChars *Others *Digits *LowChars))) ) ) ) ) ) ) )

(bye)

Test:

$ genpw --help
Generate password(s)
Options:
   --help
   --count <num>
   --length <num>
   --seed <chars>
   --exclude <chars>

$ genpw
[Rg"ia27B?M1

$ genpw  --count 4  --length 20
3O-c23;TbZ~5qAor|!6Q
+H$.bH(aqS19N85a&7aA
?|{(v1EavtB83TTl85W
U%GoEbG%p006l)|+Y1i0

PowerShell

function New-RandomPassword
{
  <#
    .SYNOPSIS
        Generates one or more passwords.
    .DESCRIPTION
        Generates one or more passwords.
    .PARAMETER Length
        The password length (default = 8).
    .PARAMETER Count
        The number of passwords to generate.
    .PARAMETER Source
        An array of strings containing characters from which the password will be generated.  The default is good for most uses.
    .PARAMETER ExcludeSimilar
        A switch which indicates that visually similar characters should be ignored.
    .EXAMPLE
        New-RandomPassword

        Generates one password of the default length (8 characters).
    .EXAMPLE
        New-RandomPassword -Count 4

        Generates four passwords each of the default length (8 characters).
    .EXAMPLE
        New-RandomPassword -Length 12 -Source abcdefghijklmnopqrstuvwxyz, ABCDEFGHIJKLMNOPQRSTUVWXYZ, 0123456789

        Generates a password with a length of 12 containing at least one char from each string in Source
    .EXAMPLE
        New-RandomPassword -Count 4 -ExcludeSimilar

        Generates four passwords each of the default length (8 characters) while excluding similar characters "Il1O05S2Z".
  #>
    [CmdletBinding()]
    [OutputType([string])]
    Param
    (
        [Parameter(Mandatory=$false)]
        [ValidateRange(1,[Int]::MaxValue)]
        [Alias("l")] 
        [int]
        $Length = 8,

        [Parameter(Mandatory=$false)]
        [ValidateRange(1,[Int]::MaxValue)]
        [Alias("n","c")] 
        [int]
        $Count = 1,
        
        [Parameter(Mandatory=$false)]
        [Alias("s")] 
        [string[]]
        $Source = @("abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "0123456789", "!\`"#$%&'()*+,-./:;<=>?@[]^_{|}~"),

        [Parameter(Mandatory=$false)]
        [Alias("x")] 
        [switch]
        $ExcludeSimilar
    )

    Begin
    {
        [char[][]] $charArrays = $Source
        [char[]]   $allChars   = $charArrays | ForEach-Object {$_}
        [char[]]   $similar    = "Il1O05S2Z".ToCharArray()

        $random = New-Object -TypeName System.Security.Cryptography.RNGCryptoServiceProvider

        function Get-Seed
        {
            $bytes = New-Object -TypeName System.Byte[] -Argument 4
            $random.GetBytes($bytes)
            [BitConverter]::ToUInt32($bytes, 0)
        }

        function Add-PasswordCharacter ([char[]]$From)
        {
            $key = Get-Seed

            while ($password.ContainsKey($key))
            {
                $key = Get-Seed                        
            }

            $index = (Get-Seed) % $From.Count

            if ($ExcludeSimilar)
            {
                while ($From[$index] -in $similar)
                {
                    $index = (Get-Seed) % $From.Count
                }
            }

            $password.Add($key, $From[$index])
        }
    }
    Process
    {
        for ($i = 1;$i -le $Count; $i++)
        {
            [hashtable] $password = @{}

            foreach ($array in $charArrays)
            {
                if($password.Count -lt $Length)
                {
                    Add-PasswordCharacter -From $array # Append to $password
                }
            }

            for ($j = $password.Count; $j -lt $Length; $j++)
            {
                Add-PasswordCharacter -From $allChars  # Append to $password
            }

            ($password.GetEnumerator() | Select-Object -ExpandProperty Value) -join "" 
        }
    }
}
New-RandomPassword -Length 12 -Count 4 -ExcludeSimilar
Output:
}[:=~f$9<Q{'
;EB$JX3/)-qq
u;DD.9t3-3]_
/4#YwjRB4-W-

Make it Unix-like:

Set-Alias -Name nrp -Value New-RandomPassword -Description "Generates one or more passwords"

nrp -l 12 -n 4 -x
Output:
]?Vwrj377tAV
g%\QEx)$3|7"
U*89)9TCKw$j
bvG7UQ3%/4F#

Prolog

Works with: SWI-Prolog version 7.6.4 or higher
:- set_prolog_flag(double_quotes, chars).
:- initialization(main, main).

main( Argv ) :-
    opt_spec( Spec ),
    opt_parse( Spec, Argv, Opts, _ ),    
    (
        member( help(true), Opts ) -> show_help
        ; 
        member( length( Len ), Opts ),
        member( number( Num ), Opts ),
        print_set_of_passwords( Len, Num )
    ).
    
show_help :-
    opt_spec( Spec ),   
    opt_help( Spec, HelpText ),
    write( 'Usage: swipl pgen.pl <options>\n\n' ),
    write( HelpText ),
    nl.    
    
opt_spec([
    [opt(help),   type(boolean), default(false), shortflags([h]), longflags([help]),   
        help('Show Help')],
    [opt(length), type(integer), default(10),    shortflags([l]), longflags([length]), 
        help('Specify the length of each password.')], 
    [opt(number), type(integer), default(1),     shortflags([n]), longflags([number]), 
        help('Specify the number of passwords to create.')]    
]).    
    
print_set_of_passwords( Length, Number ) :-
    forall(
         between( 1, Number, _ ), 
        (
            random_pword( Length, P ), 
            maplist( format('~w'), P ), 
            nl
        )
    ).

random_pword( Length, Pword ) :-
    length( GenPword, Length ),
    findall( C, pword_char( _, C), PwordChars ),
    repeat, 
    maplist(populate_pword( PwordChars ), GenPword ),
    maplist( pword_char_rule( GenPword ), [lower, upper, digits, special] ),
    random_permutation( GenPword, Pword ).
    
populate_pword( PwordChars, C ) :- random_member( C, PwordChars ).

pword_char_rule( Pword, Type ) :-
    pword_char( Type, C ),
    member( C, Pword).
    
pword_char( lower, C ) :- member( C, "abcdefghijklmnopqrstuvwxyz" ).
pword_char( upper, C ) :- member( C, "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ).
pword_char( digits, C ) :- member( C, "0123456789" ).
pword_char( special, C ) :- member( C, "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~" ).
Output:

Showing help

> swipl .\pgen.pl -h
Usage: swipl pgen.pl <options>

--help    -h  boolean=false  Show Help
--length  -l  integer=10     Specify the length of each password.
--number  -n  integer=1      Specify the number of passwords to create.

>

Default mode, one password, length of 10 characters

> swipl .\pgen.pl
Fv8sfWz-gz
> 

Specify length and number of passwords.

> swipl .\pgen.pl -l 20 -n 10
;t&qeMlw6>{rq4'0p$io
z(i0vc/h7mdszdyXo}mC
:4%Xd[8WK4Y(jg}7?X%M
f6?mpxT9blOA_=0A<b[3
5ABR=KDs&:9O;"3pi2RA
k9eXn_7G4E[_@v;;d<>J
*CX[Nr_B$jD6ZbfUCVbV
E?".8gX.!=ysIfbHW+-H
mS:!$f;-g3,8+LpF'TTH
)L:j,?Uzik:b844C@Yh!
>

PureBasic

EnableExplicit

Procedure.b CheckPW(pw.s)
  Define flag.b=#True,
         tmp.b=#False,
         c.c,
         s.s,
         i.i  
  For c='a' To 'z'
    tmp=Bool(FindString(pw,Chr(c)))
    If tmp : Break : EndIf
  Next  
  flag & tmp
  tmp=#False  
  For c='A' To 'Z'
    tmp=Bool(FindString(pw,Chr(c)))
    If tmp : Break : EndIf
  Next  
  flag & tmp
  tmp=#False  
  For c='0' To '9'
    tmp=Bool(FindString(pw,Chr(c)))
    If tmp : Break : EndIf
  Next  
  flag & tmp
  tmp=#False  
  For c='!' To '/'
    s+Chr(c)
  Next  
  For c=':' To '@'
    s+Chr(c)
  Next  
  s+"[]^_{|}~"  
  For i=1 To Len(pw)
    tmp=Bool(FindString(s,Mid(pw,i,1)))
    If tmp : Break : EndIf
  Next    
  flag & tmp  
  ProcedureReturn flag
EndProcedure

Procedure.s InputHdl(prompt.s="")
  Define txt.s,
         s.s,
         r.i,
         hlp.s  
  Restore Help_01
  Read.s hlp  
  Print(prompt)       
  Repeat
    s=Inkey()    
    If s<>""
      If FindString("0123456789",s)
        txt+s
        Print(s)
      EndIf
      If s=Chr(27)
        txt="0"
        Break
      EndIf            
    ElseIf RawKey()
      r=RawKey()      
      If r=112
        PrintN("")
        PrintN(hlp)  
        Print(~"\n"+prompt)
      EndIf
    EndIf
    Delay(20)
  Until s=Chr(13)
  PrintN("")  
  ProcedureReturn txt
EndProcedure

NewList PasswordChar.c()
Define c.c,
       pwlen.i,
       n_of_pw.i, 
       pwstr.s,
       i.i
For c='!' To '~'
  If c<>'\' And c<>'`'
    AddElement(PasswordChar()) : PasswordChar()=c
  EndIf  
Next
OpenConsole("Password generator: F1=Help; Esc=End")
Repeat
  pwlen=Abs(Val(InputHdl("Length of the password (n>=4): ")))
  If pwlen=0 : Break : EndIf
  If pwlen<4 : Continue : EndIf
  n_of_pw=Abs(Val(InputHdl("Number of passwords (n>=1): ")))
  If n_of_pw=0 : Break : EndIf  
  For i=1 To n_of_pw    
    Repeat      
      pwstr=Mid(pwstr,2)
      RandomizeList(PasswordChar())
      ResetList(PasswordChar())      
      While NextElement(PasswordChar())
        pwstr+Chr(PasswordChar())      
        If Len(pwstr)>=pwlen : Break : EndIf
      Wend
    Until CheckPW(pwstr)
    PrintN(RSet(Str(i),Len(Str(n_of_pw))," ")+") "+pwstr)
    pwstr=""
  Next
  PrintN("")
ForEver
End

DataSection
  Help_01:
  Data.s ~"Help: Password generator\n"+
         ~"------------------------\n"+
         ~"Blabla bla blabla bla blablabla.\n"+
         ~"Blabla bla  blablabla.\n"+
         ~"Bla blabla bla blablabla bla.\n"+
         ~"Blabla bla blabla bla.\n"+
         ~"Bla blabla bla blablabla blablabla.\n"+
         ~"Blabla bla blabla bla blablabla.\n"+
         ~"Blabla blabla bla blablabla."
  EndOfHelp:
EndDataSection
Output:
Length of the password (n>=4): 10
Number of passwords (n>=1): 12
 1) UteCZm/!9V
 2) R1B*C'gw&<
 3) uPDw.:FhY2
 4) v&0HD6tA);
 5) Ldspz:XcT4
 6) ^a9>Viv"R2
 7) k*x=6VCqMd
 8) y6Jz)p|^=h
 9) UO|sFD^Ry2
10) 1g5*e/:kZf
11) y;mJ{g7QX#
12) _Nh=:'V|a2

Length of the password (n>=4):

Python

import random

lowercase = 'abcdefghijklmnopqrstuvwxyz' # same as string.ascii_lowercase
uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' # same as string.ascii_uppercase
digits = '0123456789'                    # same as string.digits
punctuation = '!"#$%&\'()*+,-./:;<=>?@[]^_{|}~' # like string.punctuation but without backslash \ nor grave `

allowed = lowercase + uppercase + digits + punctuation

visually_similar = 'Il1O05S2Z'


def new_password(length:int, readable=True) -> str:
    if length < 4:
        print("password length={} is too short,".format(length),
            "minimum length=4")
        return ''
    choice = random.SystemRandom().choice
    while True:
        password_chars = [
            choice(lowercase),
            choice(uppercase),
            choice(digits),
            choice(punctuation)
            ] + random.sample(allowed, length-4)
        if (not readable or 
                all(c not in visually_similar for c in password_chars)):
            random.SystemRandom().shuffle(password_chars)
            return ''.join(password_chars)


def password_generator(length, qty=1, readable=True):
    for i in range(qty):
        print(new_password(length, readable))
Output:
>>> password_generator(14, 4)
i&H.j9F$)'V}!o
w&.U6vaf/HD;sA
i8Hfyq@&M?g:L6
j#%JxdbG9@fvX*
>>> password_generator(8, 4, readable=False)
A#f5c;(E
z@C9iIa1
R{s320IH
$4FLjCL0

Quackery

  [ [] unrot
    over - 1+ times [ i over + rot join swap ]
    drop ]                                        is range     ( n n --> [ )

  [ char a char z range ] constant                is lowers    (     --> $ )

  [ char A char Z range ] constant                is uppers    (     --> $ )

  [ char 0 char 9 range ] constant                is digits    (     --> $ )

  [ $ \!"#$%&'()*+,-./:;<=>?@[]^_{|}~\ ]          is others    (     --> $ )

  [ [] ' [ lowers uppers digits others ]
    tuck witheach
      [ do dup size random peek join ]
    [] rot witheach [ do join ]
    rot 4 - times
      [ dup dup size random peek
        rot join swap ]
    drop shuffle ]                                is password  (   n --> $ )

  [ swap times
     [ dup password echo$ cr ]  drop ]            is passwords ( n n -->   )

  [ say "'passwords' generates a specified"  cr
    say "number of passwords of a specified" cr
    say "length. For example,"               cr
                                             cr
    say "    5 10 passwords"                 cr
                                             cr
    say "will generate five ten-character"   cr
    say "passwords."                         cr ] is help

 say "Type 'help' for help with passwords."
Output:

As a dialogue in the Quackery shell.

/O> $ "rosetta/Password generator.qky" loadfile
... 
Type 'help' for help with passwords.
Stack empty.

/O> help
... 
'passwords' generates a specified
number of passwords of a specified
length. For example,

    5 10 passwords

will generate five ten-character
passwords.

Stack empty.

/O> 5 10 passwords
... 
TT7FdCQ5+x
e)MH_>-07q
2&)]'#MB|o
V%jE4<k3!|
X:v5]Y+,4W

Stack empty.

/O>

R

passwords <- function(nl = 8, npw = 1, help = FALSE) {
  if (help) return("gives npw passwords with nl characters each")
  if (nl < 4) nl <- 4
  spch <- c("!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "@", "[", "]", "^", "_", "{", "|", "}", "~")
  for(i in 1:npw) {
    pw <- c(sample(letters, 1), sample(LETTERS, 1), sample(0:9, 1), sample(spch, 1))
    pw <- c(pw, sample(c(letters, LETTERS, 0:9, spch), nl-4, replace = TRUE))
    cat(sample(pw), "\n", sep = "")
  }
}

set.seed(123)
passwords(help = TRUE)
## [1] "gives npw passwords with nl characters each"

passwords(8)
## S2XnQoy*

passwords(14, 5)
## :.iJ=Q7_gP?Cio
## !yUu7OL|eH;}1p
## y2{DNvV^Zl^IFe
## Tj@T19L.q1;I*]
## 6M+{)xV?i|1UJ/

Racket

#lang racket

(require racket/cmdline)

(define valid-uppercase '(#\A #\B #\C #\D #\E #\F #\G #\H #\I #\J
                          #\K #\L #\M #\N #\O #\P #\Q #\R #\S #\T
                          #\U #\V #\W #\X #\Y #\Z))
(define valid-lowercase '(#\a #\b #\c #\d #\e #\f #\g #\h #\i #\j
                          #\k #\l #\m #\n #\o #\p #\q #\r #\s #\t
                          #\u #\v #\w #\x #\y #\z))
(define valid-numbers '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9))
(define valid-symbols '(#\! #\\ #\" #\# #\$ #\% #\& #\' #\( #\)
                        #\* #\+ #\, #\- #\. #\/ #\: #\; #\< #\=
                        #\> #\? #\@ #\[ #\] #\^ #\_ #\{ #\| #\}
                        #\~))

(define visual-invalid '(#\0 #\O #\1 #\I #\l #\| #\5 #\S #\2 #\Z))

(define (is-readable?  c)
  (empty? (filter (lambda (x) (eq? x c)) visual-invalid)))

(define (random-selection lst)
  (list-ref lst (random (length lst))))

(define (generate len readable)
  (let ([upper (if readable (filter is-readable? valid-uppercase) valid-uppercase)]
        [lower (if readable (filter is-readable? valid-lowercase) valid-lowercase)]
        [numbers (if readable (filter is-readable? valid-numbers) valid-numbers)]
        [symbols (if readable (filter is-readable? valid-symbols) valid-symbols)])
    (let loop ([lst (map random-selection (list upper lower numbers symbols))])
      (cond
        [(<= len (length lst)) (shuffle lst)]
        [else (match (random 4)
                [0 (loop (cons (random-selection upper) lst))]
                [1 (loop (cons (random-selection lower) lst))]
                [2 (loop (cons (random-selection numbers) lst))]
                [3 (loop (cons (random-selection symbols) lst))])]))))

(define (run len cnt seed readable)
  (random-seed seed)
  (let loop ([x cnt])
    (unless (zero? x)
      (display (list->string (generate len readable)))
      (newline)
      (loop (- x 1)))))

(define len (make-parameter 10))
(define cnt (make-parameter 1))
(define seed (make-parameter (random 1 1000000)))
(define readable? (make-parameter #f))

(command-line #:program "passwdgen"
              #:once-each
              [("-l" "--length") integer "password length"  (len (string->number integer))]
              [("-c" "--count") integer "number of password" (cnt (string->number integer))]
              [("-s" "--seed") integer "random generator seed" (seed (string->number integer))]
              [("-r" "--readable") "safe characters" (readable? #t)])


(run (len) (cnt) (seed) (readable?))

Sample output:

$ racket ./passwdgen.rkt
4K{3EU30nP
$ racket ./passwdgen.rkt -l 15 -c 3 -s 1 -r
3_7tY~krwNz8MBP
966xU!&KT6mpW,M
Wh,(o*c_/Bf99K4

Raku

(formerly Perl 6)

Works with: Rakudo version 2016.05
my @chars =
  set('a' .. 'z'),
  set('A' .. 'Z'),
  set('0' .. '9'),
  set(<!"#$%&'()*+,-./:;<=>?@[]^_{|}~>.comb);

# bleh. unconfuse syntax highlighter. '"

sub MAIN ( Int :$l = 8, Int :$c = 1, Str :$x = '' ) {
    note 'Password length must be >= 4' and exit if $l < 4;
    note 'Can not generate fewer than 0 passwords' and exit if $c < 0;
    my $chars = [∪] @chars».=&filter;
    note 'Can not exclude an entire required character group' and exit
      if any(@chars».elems) == 0;
    for ^$c {
        my @pswd;
        @pswd.push( @chars[$_].roll ) for ^4;
        @pswd.push( $chars    .roll ) for 4 ..^ $l;
        say [~] @pswd.pick(*);
    }

    sub filter (Set $set) { $setset($x.comb) }
}

sub USAGE() {
    say qq:to/END/;
    Specify a length:              --l=8 (default 8),
    Specify a count:               --c=1 (default 1),
    Specify characters to exclude: --x=
    (must escape characters significant to the shell)
    E.G.
    {$*PROGRAM-NAME} --l=14 --c=5 --x=0O\\\"\\\'1l\\\|I
    END
}

Sample output: Using defaults:

c?6!xU+u

With passed parameters: --l=14 --c=5 --x=0O\'\"1l\|I

6H~jC+5(+&H44x
+Rr}2>htHMa.Y9
t~#&N]sp_zGK2#
TcP73CJ@euFMjj
9%-tYX]z?8-xA5

functional

my @char-groups =
    ['a' .. 'z'],
    ['A' .. 'Z'],
    ['0' .. '9'],
    < $ % & \ ` ~ ! * + , - . / :  ;  = ? @ ^ _  ~ [ ] ( ) { | } # ' " \< \> >.Array;

subset MinimumPasswordLength of  Int where * >= 4;
subset NumberOfPasswords     of UInt where * != 0;

sub MAIN( NumberOfPasswords :c(:$count) = 1, MinimumPasswordLength :l(:$length) = 8, Str :x(:$exclude) = '' ) {
    &USAGE() if 1 == (.comb$exclude.comb).elems for @char-groups; 
    .say for password-characters($length, $exclude )
        .map( *.split(' ') )
        .map( *.pick: Inf ) # shuffle, so we don't get a predictable pattern
        .map( *.join )
        .head( $count );
}

sub password-characters( $len, $exclude ) {
    ( (( char-groups($exclude)       xx Inf ).map: *.pick).batch(     4)
     Z~
      (( char-groups($exclude, $len) xx Inf ).map: *.pick).batch($len-4) )
}

multi char-groups( $exclude )              { | @char-groups.map( * (-) $exclude.comb ) }
multi char-groups( $exclude, $max-weight ) { flat (char-groups($exclude)>>.keys.map: {$_ xx ^$max-weight .roll}) }

sub USAGE() {
    say qq:to/END/;
    Specify a length:              -l=10    (minimum 4)
    Specify a count:               -c=5     (minimum 1)
    Specify characters to exclude: -x=xkcd  (optional)
    Password must have at least one of each: lowercase letter, uppercase letter, digit, punctuation.
   END
}

Sample output:

Without parameters:

d[G2r4;i

With passed parameters: -c=5 -l=12 -x=aeiou

x7)YbEZQ2xp2
CEpZ>#4'rO7d
pn(5B;wb66DM
KA;3T7=s+I5{
LL<tB~L1~Y*q

REXX

This REXX code was written as generically and idiomatically as possible so that the   special characters   and  
the lowercase and uppercase alphabets may be extended with letters from other alphabets.

This REXX version supports specifying a seed for the   random   BIF,   as well as specification of characters
to   not   to be used for the password.

This version isn't restricted to ASCII characters,   it also supports EBCDIC as well.

It has a REXX statement   (as a comment)   to support the writing of the generated passwords to a file.

The documentation (help) could be expanded greatly, but only an abridged version is included here to keep
this REXX example relatively small for this Rosetta Code task.

Also, much more error checking should be added;   not the least of it would be:

  •   if too many arguments specified   (on the command line)
  •   checking if the (random) seed is valid
  •   better (informative) error messages   (more verbose)
  •   don't let the user generate a gazillion passwords
  •   checking if the hexadecimal literal   (yyy)   is valid
  •   checking (for instance) if all digits were excluded via the   xxx   and/or   yyy   option
/*REXX program generates a  random password  according to the Rosetta Code task's rules.*/
@L='abcdefghijklmnopqrstuvwxyz'; @U=@L; upper @U /*define lower-, uppercase Latin chars.*/
@#= 0123456789                                   /*   "   " string of base ten numerals.*/
@@= '!"#$%&()+,-./:;<=>?@[]^{|}~' || "'"         /*define a bunch of special characters.*/
parse arg L N seed xxx yyy .                     /*obtain optional arguments from the CL*/
if L=='?'               then signal help         /*does user want documentation shown?  */
if L=='' | L==","       then L=8                 /*Not specified?  Then use the default.*/
if N=='' | N==","       then N=1                 /* "      "         "   "   "     "    */
if xxx\==''             then call weed  xxx      /*Any chars to be ignored?  Scrub lists*/
if yyy\==''             then call weed  x2c(yyy) /*Hex   "    "  "     "       "     "  */
if  datatype(seed,'W')  then call random ,,seed  /*the seed for repeatable RANDOM BIF #s*/
if \datatype(L,   'W')  then call serr  "password length, it isn't an integer: "       L
if L<4                  then call serr  "password length, it's too small  (< 4): "     L
if L>80                 then call serr  "password length, it's too large  (> 80): "    L
if \datatype(N,   'W')  then call serr  "number of passwords, it isn't an integer: "   N

    do g=1  to N;       $=                       /*generate N passwords (default is one)*/
        do k=1  for L;       z=k;   if z>4  then z=random(1,4) /*1st four parts │ random*/
        if z==1  then $=$ || substr(@L,random(1,length(@L)),1) /*append lowercase letter*/
        if z==2  then $=$ || substr(@U,random(1,length(@U)),1) /*   "   uppercase    "  */
        if z==3  then $=$ || substr(@#,random(1,length(@#)),1) /*   "    numeral        */
        if z==4  then $=$ || substr(@@,random(1,length(@@)),1) /*   "  special character*/
        end   /*k*/
                                                 /* [↓]  scrambles PW, hides gen order. */
        do a=1  for L;          b=random(1, L)   /*swap every character with another.   */
        parse var $ =(a) x +1 =(b)  y  +1        /*≡  x=substr($,a,1);  y=substr($,b,1) */
        $=overlay(x,$,b);       $=overlay(y,$,a) /*(both statements) swap two characters*/
        end  /*L+L*/                             /* [↑]  more swaps obfuscates gen order*/

    say right(g, length(N))  'password is: '  $  /*display the  Nth  password to console*/
    /*      call lineout 'GENPW.PW', $  */       /*and also write the password to a file*/     /*or not.*/
    end      /*g*/                               /* [↑]  {a comment}   fileID= GENPW.PW */
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
weed:  parse arg ig;   @L=dont(@L);   @U=dont(@U);   @#=dont(@#);   @@=dont(@@);    return
dont:  return space( translate(arg(1), , ig), 0)              /*remove chars from a list*/
serr:  say;   say '***error*** invalid'  arg(1);  exit 13     /*display an error message*/
help:  signal .; .: do j=sigL+1 to sourceline(); say strip(left(sourceline(j),79)); end /*
╔═════════════════════════════════════════════════════════════════════════════╗
║  GENPW  ?                    ◄─── shows this documentation.                 ║
║  GENPW                       ◄─── generates 1 password  (with length  8).   ║
║  GENPW len                   ◄─── generates (all) passwords with this length║
║  GENPW  ,   n                ◄─── generates     N      number of passwords. ║
║  GENPW  ,   ,  seed          ◄─── generates passwords  using a random seed. ║
║  GENPW  ,   ,    ,  xxx      ◄─── generates passwords that don't contain xxx║
║  GENPW  ,   ,    ,   ,  yyy  ◄─── generates passwords that don't contain yyy║
║                                                                             ║
╟──────────── where   [if a  comma (,)  is specified,  the default is used]:  ║
║ len     is the length of the passwords to be generated.    The default is 8.║
║         The minimum is  4,   the maximum is  80.                            ║
║ n       is the number of passwords to be generated.        The default is 1.║
║ seed    is an integer seed used for the RANDOM BIF.     (Default is random.)║
║ xxx     are characters to  NOT  be used for generating passwords.           ║
║         The default is to use  all  the  (normal)  available characters.    ║
║ yyy     (same as XXX,  except the chars are expressed as hexadecimal pairs).║
╚═════════════════════════════════════════════════════════════════════════════╝         */

output   when using the inputs of:   10   20

 1 password is:  EQG@~?~a[6
 2 password is:  2J:"Cm|ol<
 3 password is:  Io32~fa[?L
 4 password is:  r)@;2;PsZE
 5 password is:  }#H"7Rk?4{
 6 password is:  cHB8Q!%@PI
 7 password is:  a7m75132.S
 8 password is:  Qcg4>FeNb7
 9 password is:  52vHl'+HIP
10 password is:  139Vk]aIL-
11 password is:  f1g;}b/W1W
12 password is:  lC74rIv5s<
13 password is:  O9$8g1}er4
14 password is:  c|E?Uh4c8~
15 password is:  :39OK2E8u#
16 password is:  vw=+uI-X+3
17 password is:  8YhJ)BS>>~
18 password is:  Vd]ZCUw%<0
19 password is:  6([b4Qk;O7
20 password is:  5ST.}:1t@O

Ring

# Project : Password generator

chars = list(4)
strp = list(2)
password = ""
chars[1] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
chars[2] = "abcdefghijklmnopqrstuvwxyz"
chars[3] = "0123456789"
chars[4] = "!\#$%&'()*+,-./:;<=>?@[]^_{|}~"

init()
plen = number(strp[1])

for n = 1 to strp[2]
     passwords(chars)
     see "password = " + password + nl
next

func passwords(chars)
       index = 0
       password = ""
       while index < plen
                 index = index + 1
                 charsind1 = index % len(chars) + 1
                 charsind2 = random(len(chars[charsind1])-1) + 1
                 password = password + chars[charsind1][charsind2]
       end

func init()
       fp = fopen("C:\Ring\calmosoft\pwgen.ring","r")
       r = ""
       str = ""
       nr = 0
       while isstring(r)
               r = fgetc(fp)
               if r != char(10) and not feof(fp)
                  str = str + r
                  nr = nr + 1
                  strp[nr] = str
               else
                  str = ""
               ok
       end
       fclose(fp)

Output:

password = w6+Am5]N
password = e9(Ca9,I
password = u8/Ah8%H
password = c4\Nc2_J

RPL

Works with: HP version 48G
« "!" 34 CHR + "#$%&'()*+,-./:;<=>?@[]^_{|}~" + "" → chars pwd
  « { 0 0 0 0 }
     WHILE DUP2 ∑LIST 4 ≠ OR REPEAT
        RAND 4 * CEIL
        { « RAND 25 * FLOOR 65 + CHR » 
          « RAND 25 * FLOOR 97 + CHR » 
          « RAND 10 * FLOOR →STR »
          « chars RAND OVER SIZE * CEIL DUP SUB » } 
        OVER GET EVAL 'pwd' STO+
        1 PUT 
        SWAP 1 - 0 MAX SWAP
     END DROP2 pwd
» » '→PWD' STO     @ ( length → "password" )

« → length n
  « IF length 4 < THEN
       "Length must be at least 4" DOERR
    ELSE
       { }
       1 n FOR j
           WHILE length →PWD DUP SIZE length > REPEAT DROP END
           +
       NEXT
    END
» » 'PWDS' STO     @ ( length n → { "password1" .. "passwordn" } )
8 3 PWDS
Output:
1: { "v7-c8d.B" "oVe1M$17" "R+I6vJ9j" }

Ruby

ARRS = [("a".."z").to_a,
        ("A".."Z").to_a, 
        ("0".."9").to_a,
        %q(!"#$%&'()*+,-./:;<=>?@[]^_{|}~).chars] # " quote to reset clumsy code colorizer
ALL  = ARRS.flatten

def generate_pwd(size, num)
  raise ArgumentError, "Desired size too small" unless size >= ARRS.size
  num.times.map do
    arr = ARRS.map(&:sample)
    (size - ARRS.size).times{ arr << ALL.sample}
    arr.shuffle.join
  end
end

puts generate_pwd(8,3)

Run BASIC

a$(1) = "0123456789"
a$(2) = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
a$(3) = "abcdefghijklmnopqrstuvwxyz"
a$(4) = "!""#$%&'()*+,-./:;<=>?@[]^_{|}~"
a$(0) = a$(1) + a$(2) + a$(3) + a$(4)
 
[main]
print "----------- Password Generator -----------"
input "Number of Characters:";howBig
if howBig < 1 then goto [exit]
 
input "How many to generate:";howMany
if howMany < 1 then goto [main]

' -----------------------------
' Generate Password
' -----------------------------
[gen]
cls
print "Generate ";howMany;" passwords with ";howBig;" characters"
i = 0
while i < howMany
	pw$	= ""
	ok$	= "...."
	pw$	= ""
	for j = 1 to howBig
	 	w$ = mid$(a$(0),int(rnd(0) * len(a$(0))) + 1,1)
		for k = 1 to 4
			if instr(a$(k),w$) then ok$ = left$(ok$,k-1) + "*" + mid$(ok$,k+1)
	 	next k
	 	pw$ = pw$ + w$
	next j
	if ok$ = "****" then	' Do we pass with the requirements
		i	= i + 1
		print "#";i;" ";pw$
	end if
WEND
goto [main]
[exit]	' get outta here
end

Output:

Generate 10 passwords with 7 characters
#1 69+;Jj8
#2 80+T_e9
#3 1NEy[7e
#4 vj4~EvD
#5 3E(852y
#6 Cxjo]5R
#7 Hm5'tF+
#8 %i^<N7>
#9 9P8Qx_P
#10 f0Qho:5

Rust

use rand::distributions::Alphanumeric;
use rand::prelude::IteratorRandom;
use rand::{thread_rng, Rng};
use std::iter;
use std::process;
use structopt::StructOpt;
const OTHER_VALUES: &str = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~";

// the core logic that creates our password
fn generate_password(length: u8) -> String {
    // cache thread_rng for better performance
    let mut rng = thread_rng();
    // the Alphanumeric struct provides 3/4
    // of the characters for passwords
    // so we can sample from it
    let mut base_password: Vec<char> = iter::repeat(())
        .map(|()| rng.sample(Alphanumeric))
        .take(length as usize)
        .collect();
    let mut end_range = 10;
    // if the user supplies a password length less than 10
    // we need to adjust the random sample range
    if length < end_range {
        end_range = length;
    }
    // create a random count of how many other characters to add
    let mut to_add = rng.gen_range(1, end_range as usize);
    loop {
        // create an iterator of required other characters
        let special = OTHER_VALUES.chars().choose(&mut rng).unwrap();
        to_add -= 1;
        base_password[to_add] = special;
        if to_add == 0 {
            break;
        }
    }
    base_password.iter().collect()
}

#[derive(StructOpt, Debug)]
#[structopt(name = "password-generator", about = "A simple password generator.")]
struct Opt {
    // make it SECURE by default
    // https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html
    /// The password length
    #[structopt(default_value = "160")]
    length: u8,
    /// How many passwords to generate
    #[structopt(default_value = "1")]
    count: u8,
}

fn main() {
    // instantiate the options and use them as
    // arguments to our password generator
    let opt = Opt::from_args();
    const MINIMUM_LENGTH: u8 = 30;
    if opt.length < MINIMUM_LENGTH {
        eprintln!(
            "Please provide a password length greater than or equal to {}",
            MINIMUM_LENGTH
        );
        process::exit(1);
    }
    for index in 0..opt.count {
        let password = generate_password(opt.length);
        // do not print a newline after the last password
        match index + 1 == opt.count {
            true => print!("{}", password),
            _ => println!("{}", password),
        };
    }
}
Output:
password-generator 30 5

%"/[:*|}zYNaC2C7IRsAXK8zDZR8JC
)fJGVcMqBLQkU5x2YOpo6Oyw0ezWHh
%/@&@2BBOQBLnH74lsqtj92eWZRQzc
|:%!r77MTosArmxe9J3LvKurcdOX3P
(=>#[!%|z84tH5edhGY48hoylopnIA

Scala

Using SBT to run rather than a shell script or executable jar:

object makepwd extends App {

  def newPassword( salt:String = "", length:Int = 13, strong:Boolean = true ) = {

    val saltHash = salt.hashCode & ~(1 << 31)
    
    import java.util.Calendar._

    val cal = java.util.Calendar.getInstance()
    val rand = new scala.util.Random((cal.getTimeInMillis+saltHash).toLong)
    val lower = ('a' to 'z').mkString
    val upper = ('A' to 'Z').mkString
    val nums = ('0' to '9').mkString
    val strongs = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~"
    val unwanted = if( strong ) "" else "0Ol"
    
    val pool = (lower + upper + nums + (if( strong ) strongs else "")).
               filterNot( c => unwanted.contains(c) )
    
    val pwdStream = Stream.continually( (for( n <- 1 to length; c = pool(rand.nextInt(pool.length) ) ) yield c).mkString )

    // Drop passwords that don't have at least one of each required character
    pwdStream.filter( pwd => 
      pwd.exists(_.isUpper) &&
      pwd.exists(_.isLower) &&
      pwd.exists(_.isDigit) &&
      (if(strong) pwd.exists(! _.isLetterOrDigit) else true)
    ).head
  }

  val pwdLength = """^(\d{1,4})$""".r
  val howMany = """^\-n(\d{0,3})$""".r
  val help = """^\-\-(help)$""".r
  val pwdSalt = """^\-s(.*)""".r
  val strongOption = """(?i)(strong)""".r
  
  
  var (salt,length,strong,helpWanted,count,unknown) = ("",13,false,false,1,false)
  
  args.foreach{ 
    case pwdLength(l) =>    length = math.min(math.max(l.toInt,6),4000)
    case strongOption(s) => strong = true
    case pwdSalt(s) =>      salt = s
    case howMany(c) =>      count = math.min(c.toInt,100)
    case help(h) =>         helpWanted = true
    case _ =>               unknown = true
  }

  if( count > 1 ) println
  
  if( helpWanted || unknown ) {
    println( """
  makepwd <length> "strong" -s<salt> -n<how-many> --help

    <length>     = how long should the password be
    "strong"     = strong password, omit if special characters not wanted
    -s<salt>     = "-s" followed by any non-blank characters 
                     (increases password randomness)
    -n<how-many> = "-n" followed by the number of passwords wanted
    --help       = displays this
    
  For example: makepwd 13 strong -n20 -sABCDEFG
""".stripMargin )
  }
  else for( i <- 1 to count ) println( newPassword( i + salt, length, strong ) )

  if( count > 1 ) println  
}
Output:

> sbt "run --help"

...

  makepwd <length> "strong" -s<salt> -n<how-many> --help

    <length>     = how long should the password be
    "strong"     = strong password, omit if special characters not wanted
    -s<salt>     = "-s" followed by any non-blank characters
                     (increases password randomness)
    -n<how-many> = "-n" followed by the number of passwords wanted
    --help       = displays this

  For example: makepwd 13 strong -n20 -sABCDEFG

> sbt "run 13 strong -sMySecret -n3"

...

}mR46_*cOq&v0
Ab~A!ddH8%JPd
z{A.m+$cqy#9I

Seed7

$ include "seed7_05.s7i";

const func string: generate (in integer: length) is func
  result
    var string: password is "";
  local
    const set of char: allowed is {'!' .. '~'} - {'\\', '`'};
    const set of char: special is allowed - {'A' .. 'Z'} | {'a' .. 'z'} | {'0' .. '9'};
    var integer: index is 0;
    var char: ch is ' ';
    var boolean: ucPresent is FALSE;
    var boolean: lcPresent is FALSE;
    var boolean: digitPresent is FALSE;
    var boolean: specialPresent is FALSE;
  begin
    repeat
      password := "";
      ucPresent := FALSE;
      lcPresent := FALSE;
      digitPresent := FALSE;
      specialPresent := FALSE;
      for index range 1 to length do
        ch := rand(allowed);
        ucPresent := ucPresent or ch in {'A' .. 'Z'};
        lcPresent := lcPresent or ch in {'a' .. 'z'};
        digitPresent := digitPresent or ch in {'0' .. '9'};
        specialPresent := specialPresent or ch in special;
        password &:= ch;
      end for;
    until ucPresent and lcPresent and digitPresent and specialPresent;
  end func;

const proc: main is func
  local
    var integer: length is 0;
    var integer: count is 0;
  begin
    if length(argv(PROGRAM)) <> 2 or not isDigitString(argv(PROGRAM)[1]) or
       not isDigitString(argv(PROGRAM)[2]) then 
      writeln("Usage: pwgen length count");
      writeln("       pwgen -?");
      writeln("length: The length of the password (min 4)");
      writeln("count:  How many passwords should be generated");
      writeln("-?  Write this text");
    else
      length := integer(argv(PROGRAM)[1]);
      count := integer(argv(PROGRAM)[2]);
      if length < 4 then
        writeln("Passwords must be at least 4 characters long.");
      else
        for count do
          writeln(generate(length));
        end for;
      end if;
    end if;
  end func;
Output:
$ pwgen -?
Usage: pwgen length count
       pwgen -?
length: The length of the password (min 4)
count:  How many passwords should be generated
-?  Write this text
$ pwgen 8 3
S1uqOqU~
@m'-.D,9
>tl1fvEU
$

Swift

Swift uses arc4random() to generate fast and high quality random numbers. However the usage of a user defined seed is not possible within arc4random(). To fulfill the requirements this code uses the C functions srand() and rand() that are integrated into the Swift file via an Bridging-Header.

C file to generate random numbers

#include <stdlib.h>
#include <time.h>

void initRandom(const unsigned int seed){
    if(seed==0){
        srand((unsigned) time(NULL));
    }
    else{
        srand(seed);
    }
}

int getRand(const int upperBound){
    return rand() % upperBound;
}

Bridging-Header to include C file into Swift

int getRand(const int upperBound);
void initRandom(const unsigned int seed);

Swift file

import Foundation
import GameplayKit  // for use of inbuilt Fisher-Yates-Shuffle

/* Prints the usage of this code */
func printHelp() -> Void {
    print("Usage: PasswordGenerator [-l:length] [-c:count] [-s:seed] [-x:exclude] [-h:help]")
    print("\t-l: length of the passwords (at leas 4 characters)")
    print("\t-c: number of passwords to generate")
    print("\t-s: seed of the random number generator")
    print("\t-x: exclude of visually similar characters \"Il1O05S2Z\"")
    print("\t-h: print this help")
    exit(0)
}

/* Set characters for generating passwords */
let _lower:String = "abcdefghijklmnopqrstuvwxyz"
let _lowerWithoutSimilar:String = "abcdefghijkmnopqrstuvwxyz"
let _upper:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
let _upperWithoutSimilar = "ABCDEFGHJKLMNPQRTUVWXY"
let _number:String = "0123456789"
let _numerWithoutSimilar:String = "1346789"
let _other:String = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~"

/* Generate character arrays out of strings */
let upper = Array(_upper.characters)
let upperWithoutSimilar = Array(_upperWithoutSimilar.characters)
let lower = Array(_lower.characters)
let lowerWithoutSimilar = Array(_lowerWithoutSimilar.characters)
let other = Array(_other.characters)
let number = Array(_number.characters)
let numberWithoutSimilar = Array(_numerWithoutSimilar.characters)

var length:Int=0, count:Int=0, seed:Int=0, xclude:Bool=false

/* Parse CLI arguments */
for i in 1..<CommandLine.arguments.count{
    var arg = CommandLine.arguments[i]
    var argument = arg.components(separatedBy: ":")
    switch(argument[0]){
    case "-l":
        length=Int(argument[1])!
        if length < 4 {
            print("A password must contain of at least 4 characters.")
            exit(-1)
        }
        break
    case "-c":
        count=Int(argument[1])!
        break
    case "-s":
        seed=Int(argument[1])!
        break
    case "-x":
        xclude=true
        break
    case "-h":
        printHelp()
    default:
        print("Could not parse CLI arguments. Use -h for help.")
        exit(0)
    }
}

/* Generate password of given length */
func generatePassword(length len:Int, exclude xcl:Bool) -> String{
    
    var ret:String = "", loopCount:Int = 0
    
    while(loopCount < len){
        if ret.characters.count < len {
            if xcl {
                ret += String(upperWithoutSimilar[Int(getRand(Int32(upperWithoutSimilar.count-1)))])
            }
            else {
                ret += String(upper[Int(getRand(Int32(upper.count)))])
            }
        }
        
        if ret.characters.count < len {
            if xcl {
                ret += String(lowerWithoutSimilar[Int(getRand(Int32(lowerWithoutSimilar.count-1)))])
            }
            else {
                ret += String(lower[Int(getRand(Int32(lower.count-1)))])
            }
        }
        
        if ret.characters.count < len {
            if xcl {
                ret += String(numberWithoutSimilar[Int(getRand(Int32(numberWithoutSimilar.count-1)))])
            }
            else {
                ret += String(number[Int(getRand(Int32(number.count-1)))])
            }
        }
        
        if ret.characters.count < len {
            ret += String(other[Int(getRand(Int32(other.count-1)))])
        }
        loopCount += 4
    }
    
    // Shuffle the array with an internal shuffle function
    let shuffled = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: Array(ret.characters))
    ret = ""
    for element in shuffled {
        ret += String(describing: element)
    }
    return ret
}

if xclude {
    print("Generating \(count) passwords with length \(length) excluding visually similar characters...")
}
else {
    print("Generating \(count) passwords with length \(length) not excluding visually similar characters...")
}

initRandom(UInt32(0))    // initialize with C func srand()

// generate the passwords
for i in 1...count {
    print("\(i).\t\(generatePassword(length:length,exclude:xclude))")
}
Output:
$ PasswordGenerator -h
Usage: PasswordGenerator [-l:length] [-c:count] [-s:seed] [-x:exclude] [-h:help]
	-l: length of the passwords (at leas 4 characters)
	-c: number of passwords to generate
	-s: seed of the random number generator
	-x: exclude of visually similar characters "Il1O05S2Z"
	-h: print this help

$ PasswordGenerator -l:10 -c:5 -x
Generating 5 passwords with length 10 excluding visually similar characters...
1.	Fs7]r)N4Ap
2.	(o6GgXE=6a
3.	A!A7k|N3mi
4.	6]XDKo!nx8
5.	Gi6b>6Mv&C

VBA

Option Explicit
Sub Main()
Dim s() As String, i As Long
        Debug.Print "list of 10 passwords : "
'do a list of 10 passwords with password's lenght = 21 and visually similar = False
    s = Gp(10, 21, False)
        'return
        Debug.Print "1- with password's lenght = 21 and visually similar = False :"
        For i = 1 To UBound(s): Debug.Print s(i): Next
'do a list of 10 passwords with pattern = "A/9-a/1-9/4-!/5" and visually similar = True
    s = Gp(10, "A/9-a/1-9/4-!/5", True)
        'return
        Debug.Print "2- with pattern = ""A/9-a/1-9/4-!/5"" and visually similar = True :"
        For i = 1 To UBound(s): Debug.Print s(i): Next
End Sub
Sub HelpMe()
Dim s As String
    s = "Help :" & vbCrLf
    s = s & "----------------------------------" & vbCrLf
    s = s & "The function (named : Gp) needs 3 required parameters :" & vbCrLf & vbCrLf
    s = s & "1- Nb_Passwords (Long) : the number of passwords to generate." & vbCrLf & vbCrLf
    s = s & "2- NbChar_Or_Pattern (Variant) : either a number or a pattern" & vbCrLf
    s = s & "      If number : NbChar_Or_Pattern specify the password length. All the digits are random ASCII characters" & vbCrLf
    s = s & "      If pattern : NbChar_Or_Pattern specify the password length and the layout of passwords." & vbCrLf
    s = s & "             The pattern is built like this :" & vbCrLf
    s = s & "                 ""A"" means Upper case, ""a"" means lower case, 9 means numerics and ! means others characters." & vbCrLf
    s = s & "                 ""-"" is the separator between these values." & vbCrLf
    s = s & "                 the number of characters is specified after the sign (required): ""/""" & vbCrLf
    s = s & "                 example of pattern available : ""A/3-a/2-9/1-!/1""" & vbCrLf & vbCrLf
    s = s & "3- Excl_Similar_Chars (Boolean) : True if you want the option of excluding visually similar characters."
    Debug.Print s
End Sub
Private Function Gp(Nb_Passwords As Long, NbChar_Or_Pattern As Variant, Excl_Similar_Chars As Boolean) As String()
'generate a list of passwords
Dim l As Long, s() As String
    ReDim s(1 To Nb_Passwords)
    If IsNumeric(NbChar_Or_Pattern) Then
        For l = 1 To Nb_Passwords
            s(l) = p(CLng(NbChar_Or_Pattern), Excl_Similar_Chars)
        Next l
    Else
        For l = 1 To Nb_Passwords
            s(l) = ttt(CStr(NbChar_Or_Pattern), Excl_Similar_Chars)
        Next l
    End If
    Gp = s
End Function
Public Function p(n As Long, e As Boolean) As String
'create 1 password without pattern (just with the password's lenght)
Dim t As String, i As Long, a As Boolean, b As Boolean, c As Boolean, d As Boolean
    Randomize Timer
    If n < 4 Then
        p = "Error. Numbers of characters is too small. Min : 4"
    ElseIf n >= 4 And n < 7 Then
        T = u(122, 97) & u(90, 65) & u(57, 48) & v
        For j = 5 To n
            i = Int((4 * Rnd) + 1)
            Select Case i
                Case 1: T = T & u(122, 97)
                Case 2: T = T & u(90, 65)
                Case 3: T = T & u(57, 48)
                Case 4: T = T & v
            End Select
        Next j
        'Debug.Print T
        p = y(T)
    Else
        Do
            i = Int((4 * Rnd) + 1)
            Select Case i
                Case 1: t = t & u(122, 97): a = True
                Case 2: t = t & u(90, 65): b = True
                Case 3: t = t & u(57, 48): c = True
                Case 4: t = t & v: d = True
            End Select
            If Len(t) >= 2 And e Then
                If x(t) Then t = Left(t, Len(t) - 1)
            End If
            If Len(t) = n Then
                If a And b And c And d Then
                    Exit Do
                Else
                    w t, a, b, c, d
                    p = p(n, e)
                End If
            ElseIf Len(t) > n Then
                w t, a, b, c, d
                p = p(n, e)
            End If
        Loop
        p = t
    End If
End Function
Public Function ttt(s As String, e As Boolean) As String
'create 1 password with pattern
Dim a, i As Long, j As Long, st As String, Nb As Long
    a = Split(s, "-")
    For i = 0 To UBound(a)
        Select Case Left(a(i), 1)
            Case "A"
                Nb = CLng(Split(a(i), "/")(1)): j = 0
                Do
                    j = j + 1
                    st = st & u(90, 65)
                    If Len(st) >= 2 And e Then
                        If x(st) Then st = Left(st, Len(st) - 1): j = j - 1
                    End If
                Loop While j < Nb
            Case "a"
                Nb = CLng(Split(a(i), "/")(1)): j = 0
                Do
                    j = j + 1
                    st = st & u(122, 97)
                    If Len(st) >= 2 And e Then
                        If x(st) Then st = Left(st, Len(st) - 1): j = j - 1
                    End If
                Loop While j < Nb
            Case "9"
                Nb = CLng(Split(a(i), "/")(1)): j = 0
                Do
                    j = j + 1
                    st = st & u(57, 48)
                    If Len(st) >= 2 And e Then
                        If x(st) Then st = Left(st, Len(st) - 1): j = j - 1
                    End If
                Loop While j < Nb
            Case "!"
                Nb = CLng(Split(a(i), "/")(1)): j = 0
                Do
                    j = j + 1
                    st = st & v
                    If Len(st) >= 2 And e Then
                        If x(st) Then st = Left(st, Len(st) - 1): j = j - 1
                    End If
                Loop While j < Nb
        End Select
    Next i
    ttt = y(st)
End Function
Private Function u(m As Long, l As Long) As String
'random 1 character in lower/upper case or numeric
    Randomize Timer
    u = Chr(Int(((m - l + 1) * Rnd) + l))
End Function
Private Function v() As String
'random 1 character "special"
    Randomize Timer
    v = Mid("!""#$%&'()*+,-./:;<=>?@[]^_{|}~", Int((30 * Rnd) + 1), 1)
End Function
Private Sub w(t As String, a As Boolean, b As Boolean, c As Boolean, d As Boolean)
    t = vbNullString: a = False: b = False: c = False: d = False
End Sub
Private Function x(s As String) As Boolean
'option of excluding visually similar characters
Dim t, i As Long
Const d As String = "Il I1 l1 lI 1l 1I 0O O0 5S S5 2Z 2? Z? Z2 ?2 ?Z DO OD"
    t = Split(d, " ")
    For i = 0 To UBound(t)
        If Right(s, 2) = t(i) Then
            x = True: Exit Function
        End If
    Next
End Function
Private Function y(s As String) As String
'shuffle the password's letters only if pattern
Dim i&, t, r As String, d() As Long
    t = Split(StrConv(s, vbUnicode), Chr(0))
    d = z(UBound(t))
    For i = 0 To UBound(t)
        r = r & t(d(i))
    Next i
    y = Left(r, Len(r) - 1)
End Function
Private Function z(l As Long) As Long()
'http://rosettacode.org/wiki/Best_shuffle#VBA
Dim i As Long, ou As Long, temp() As Long
Dim c As New Collection
    ReDim temp(l)
    If l = 1 Then
        temp(0) = 0
    ElseIf l = 2 Then
        temp(0) = 1: temp(1) = 0
    Else
        Randomize
        Do
            ou = Int(Rnd * l)
            On Error Resume Next
            c.Add CStr(ou), CStr(ou)
            If Err <> 0 Then
                On Error GoTo 0
            Else
                temp(ou) = i
                i = i + 1
            End If
        Loop While c.Count <> l
    End If
    z = temp
End Function
Output:

Function Gp :

list of 10 passwords : 
1- with password's lenght = 21 and visually similar = False :
;OK6^D26"S1^ih77<pR~v
EH9csF8+hC"pw70dL5},A
F1qIC#xXZ!%mQ2kb5&>q1
c|e0*emQ2-bN1}QL-fFB3
/U9)@J54zY44(gI,/vZ5t
3W:!y44(n36nc2<"KW5)Z
7[oOK6^D26"S1^ih77<pR
zveH9csF8+hC"pw70dL5}
,A21qIC#xXZ!%mQ2kb5&>
=11|e0*emQ2-bN1}QL-fF
2- with pattern = "A/9-a/1-9/4-!/5" and visually similar = True :
)C4N#<>r@NDUX094LKF
EJL~!:JKS39U3<AW5"s
H$0t?1'V7+DHV#WFQQ8
71!t0T)BSGZ|V=>KI9V
I50GN^"+T8Vs>E"NKI1
|JAOrWY"WW97_7[Y[2K
EBoB/3)C#Z$F6U3V1,O
ANOBPZ*X2I-3@H]58e:
7D1$7V+BHQH'FV0#w{Q
&%72&LFL6iS~C(HAPQ8

Sub HelpMe :

Help :
----------------------------------
The function (named : Gp) needs 3 required parameters :

1- Nb_Passwords (Long) : the number of passwords to generate.

2- NbChar_Or_Pattern (Variant) : either a number or a pattern
      If number : NbChar_Or_Pattern specify the password length. All the digits are random ASCII characters
      If pattern : NbChar_Or_Pattern specify the password length and the layout of passwords.
             The pattern is built like this :
                 "A" means Upper case, "a" means lower case, 9 means numerics and ! means others characters.
                 "-" is the separator between these values.
                 the number of characters is specified after the sign (required): "/"
                 example of pattern available : "A/3-a/2-9/1-!/1"

3- Excl_Similar_Chars (Boolean) : True if you want the option of excluding visually similar characters.

Wren

Translation of: Kotlin
Library: Wren-ioutil
Library: Wren-fmt
import "random" for Random
import "./ioutil" for FileUtil, File, Input
import "./fmt" for Fmt
import "os" for Process

var r  = Random.new()
var rr = Random.new() // use a separate generator for shuffles
var lb = FileUtil.lineBreak

var lower = "abcdefghijklmnopqrstuvwxyz"
var upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
var digit = "0123456789"
var other = """!"#$%&'()*+,-./:;<=>?@[]^_{|}~"""

var exclChars = [
    "'I', 'l' and '1'",
    "'O' and '0'     ",
    "'5' and 'S'     ",
    "'2' and 'Z'     "
]

var shuffle = Fn.new { |s|
    var sl = s.toList
    rr.shuffle(sl)
    return sl.join()
}

var generatePasswords = Fn.new { |pwdLen, pwdNum, toConsole, toFile|
    var ll = lower.count
    var ul = upper.count
    var dl = digit.count
    var ol = other.count
    var tl = ll + ul + dl + ol
    var fw = toFile ? File.create("pwds.txt") : null
 
    if (toConsole) System.print("\nThe generated passwords are:")
    for (i in 0...pwdNum) {
        var pwd = lower[r.int(ll)] + upper[r.int(ul)] + digit[r.int(dl)] + other[r.int(ol)]
        for (j in 0...pwdLen - 4) {
            var k = r.int(tl)
            pwd = pwd + ((k < ll)      ? lower[k] :
                         (k < ll + ul) ? upper[k - ll] :
                         (k < tl - ol) ? digit[k - ll - ul] : other[tl - 1 - k])
        }
        for (i in 1..5) pwd = shuffle.call(pwd) // shuffle 5 times say
        if (toConsole) Fmt.print("  $2d: $s", i + 1, pwd)
        if (toFile) {
            fw.writeBytes(pwd)
            if (i < pwdNum - 1) fw.writeBytes(lb)
        }
    }
    if (toFile) {
       System.print("\nThe generated passwords have been written to the file pwds.txt")
       fw.close()
    }
}

var printHelp = Fn.new {
    System.print("""
This program generates up to 99 passwords of between 5 and 20 characters in
length.

You will be prompted for the values of all parameters when the program is run
- there are no command line options to memorize.

The passwords can either be written to the console or to a file (pwds.txt),
or both.

The passwords must contain at least one each of the following character types:
   lower-case letters :  a -> z
   upper-case letters :  A -> Z
   digits             :  0 -> 9
   other characters   :  !"#$%&'()*+,-./:;<=>?@[]^_{|}~

Optionally, a seed can be set for the random generator
(any non-zero number) otherwise the default seed will be used.
Even if the same seed is set, the passwords won't necessarily be exactly
the same on each run as additional random shuffles are always performed.

You can also specify that various sets of visually similar characters
will be excluded (or not) from the passwords, namely: Il1  O0  5S  2Z

Finally, the only command line options permitted are -h and -help which
will display this page and then exit.

Any other command line parameters will simply be ignored and the program
will be run normally.

""")
}

var args = Process.arguments
if (args.count == 1 && (args[0] == "-h" || args[0] == "-help")) {
   printHelp.call()
   return
}

System.print("Please enter the following and press return after each one")

var pwdLen = Input.integer("  Password length (5 to 20)     : ", 5, 20)
var pwdNum = Input.integer("  Number to generate (1 to 99)  : ", 1, 99)

var seed   = Input.number ("  Seed value (0 to use default) : ")
if (seed != 0) r = Random.new(seed)

System.print("  Exclude the following visually similar characters")
for (i in 0..3) {
    var yn = Input.option("    %(exclChars[i]) y/n : ", "ynYN")
    if (yn == "y" || yn == "Y") {
        if (i == 0) {
            upper = upper.replace("I", "")
            lower = lower.replace("l", "")
            digit = digit.replace("1", "")
        } else if (i == 1) {
            upper = upper.replace("O", "")
            digit = digit.replace("0", "")
        } else if (i == 2) {
            upper = upper.replace("S", "")
            digit = digit.replace("5", "")
        } else if (i == 3) {
            upper = upper.replace("Z", "")
            digit = digit.replace("2", "")
        }
    }
}

var toConsole = Input.option("  Write to console   y/n : ", "ynYN")
toConsole = toConsole == "y" || toConsole == "Y"
var toFile = true
if (toConsole) {
    toFile = Input.option("  Write to file      y/n : ", "ynYN")
    toFile = toFile == "y" || toFile == "Y"
}

generatePasswords.call(pwdLen, pwdNum, toConsole, toFile)
Output:

Sample run:

Please enter the following and press return after each one
  Password length (5 to 20)     : 8
  Number to generate (1 to 99)  : 10
  Seed value (0 to use default) : 0
  Exclude the following visually similar characters
    'I', 'l' and '1' y/n : n
    'O' and '0'      y/n : n
    '5' and 'S'      y/n : n
    '2' and 'Z'      y/n : n
  Write to console   y/n : y
  Write to file      y/n : y

The generated passwords are:
   1: 53oR=Y|#
   2: LdT,[7x=
   3: puQwj#0N
   4: kY0:zL~m
   5: 01BN!fqZ
   6: +3Si33[}
   7: !MV:9/wC
   8: gcAY0m#_
   9: h45R)A|c
  10: SGrpk:86

The generated passwords have been written to the file pwds.txt

x86-64 Assembly

fasm syntax

format ELF64 executable 3
entry main
minlen  equ    8
cmdno   equ    3
cmdnos  equ    cmdno * 8

segment executable readable
main:
    mov  rax, qword [rsp]
    mov  rdi, cmdno
    cmp  rax, rdi
    cmovg rax, rdi
    cmp  rax, 1
    jle .printhelp
    cmp  rax, 2
    jg   .cmdloop
    mov  rdi, default
    mov  qword [cmdslot + 16], rdi
 .cmdloop:
    mov  rdi, qword [rsp + rax * 8]
    dec  rax
    mov  qword [cmdslot + rax * 8], rdi
    or   rax, rax
    jnz  .cmdloop
 .convert0:
    mov  rdi, qword [cmdslot + 8]
    call atoq
    cmp  rax, minlen
    jl  .printhelp
    mov  qword [cmdslot + 8], rax
    mov  rdi, qword [cmdslot + 16]
    call atoq
    sub  rax, 0
    jle  .printhelp
    mov  qword [cmdslot + 16], rax
 .allocate:
    mov  rax, qword [cmdslot + 8]
    xor  rdx, rdx
    mov  rdi, 8
    div  rdi
    add  rax, 1
    xor  rdx, rdx
    mul  rdi
    mov  qword [cmdslot], rax
    sub  rsp, rax
    mov  rax, qword [cmdslot + 16]
    mov  rdi, rsp
 .loop00:
    mov  rsi, qword [cmdslot + 8]
    call mkpass
    call check
    or  r9, r9
    jz   .loop00
    call prints
    dec  rax
    jnz .loop00
 .exit:
    add  rsp, qword [cmdslot]
    mov  rax, 60
    xor  rdi, rdi
    syscall
 .printhelp:
    mov rdi, helpmsg
    call prints
    jmp .exit

prints:
    push rdx
    push rsi
    push rdi
    push rax
    xor  rdx, rdx
    cmp  byte [rdi + rdx], 0
    je   .return
  .stloop:
    cmp  byte [rdi + rdx], 0
    je   .printit
    inc  rdx
    jmp  .stloop
  .printit:
    mov rax, 1
    mov rsi, rdi
    mov rdi, 1
    syscall
    mov al, 0x0a
    push rax
    mov rax, 1
    mov rsi, rsp
    mov rdx, 1
    syscall
    pop rax
  .return:
    pop rax
    pop rdi
    pop rsi
    pop rdx
    ret

atoq:
    push r8
    push r9
    push rdi
    push rsi
    push rdx
    push rcx
    xor rax, rax
    xor r8, r8
    mov r9, 1
    cmp byte[rdi], 0
    jz .exit
    cmp byte[rdi], '-'
    jne .stloop
    mov r9, -1
    inc rdi
  .stloop:
    cmp byte[rdi + r8], '0'
    jl .calc0
    cmp byte[rdi + r8], '9'
    jg .calc0
    mov sil, byte[rdi + r8]
    sub rsi, '0'
    push rsi
    inc r8
    jmp .stloop
  .calc0:
    xor rcx, rcx
    mov rdi,  10
    mov rsi, 1
  .calc1:
    pop rax
    mul rsi
    add rcx, rax
    dec r8
    jz  .return
    mov rax, rsi
    mul rdi
    mov rsi, rax
    jmp .calc1
  .return:
    mov rax, rcx
    imul r9
  .exit:
    pop rcx
    pop rdx
    pop rsi
    pop rdi
    pop r9
    pop r8
    ret

getchar:
    push rdi
    push rdx
    rdrand rax
    mov  rdi, endchars - chars
    xor  rdx, rdx
    div  rdi
    xor  rax, rax
    mov  al, byte [chars + rdx]
    pop  rdx
    pop  rdi
    ret

mkpass:
    push rsi
    push rax
    mov  byte [rdi + rsi], 0
 .loop0:
    dec  rsi
    call getchar
    mov  byte [rdi + rsi], al
    or   rsi, rsi
    jnz .loop0
 .return0:
    pop  rax
    pop  rsi
    ret

check:
    push rax
    push rdx
    push rcx
    xor  r9, r9
 .upper:
    xor  rcx, rcx
 .upper0:
    xor  rdx, rdx
    mov  rsi, endalphau - alphau
    mov  al, byte[rdi + rcx]
 .upper1:
    cmp  al, byte[alphau + rdx]
    je   .lower
    inc  rdx
    cmp  rdx, rsi
    jl   .upper1
    inc  rcx
    cmp  byte[rdi + rcx], 0
    jnz  .upper0
    jmp  .return0
 .lower:
    xor  rcx, rcx
 .lower0:
    xor  rdx, rdx
    mov  rsi, endalphal - alphal
    mov  al, byte[rdi + rcx]
 .lower1:
    cmp  al, byte[alphal + rdx]
    je   .numeric
    inc  rdx
    cmp  rdx, rsi
    jl   .lower1
    inc  rcx
    cmp  byte[rdi + rcx], 0
    jnz  .lower0
    jmp  .return0
 .numeric:
    xor  rcx, rcx
 .numeric0:
    xor  rdx, rdx
    mov  rsi, endnumeri - numeri
    mov  al, byte[rdi + rcx]
 .numeric1:
    cmp  al, byte[numeri + rdx]
    je   .special
    inc  rdx
    cmp  rdx, rsi
    jl   .numeric1
    inc  rcx
    cmp  byte[rdi + rcx], 0
    jnz  .numeric0
    jmp  .return0
 .special:
    xor  rcx, rcx
 .special0:
    xor  rdx, rdx
    mov  rsi, endspecia - specia
    mov  al, byte[rdi + rcx]
 .special1:
    cmp  al, byte[specia + rdx]
    je   .return1
    inc  rdx
    cmp  rdx, rsi
    jl   .special1
    inc  rcx
    cmp  byte[rdi + rcx], 0
    jnz  .special0
    jmp  .return0
 .return1:
    mov  r9, 1
 .return0:
    pop  rcx
    pop  rdx
    pop  rax
    ret

segment readable
helpmsg:
        db "Usage:", 0x0a
        db "passgen nchars [ncount]", 0x0a, 0x0a
        db "nchars = number of characters for each password", 0x0a
        db "ncount = number of passwords to generate", 0x0a
        db "If ncount is omitted, a default of 1 will be used.", 0x0a, 0x0a
        db "A password generation program which will generate passwords", 0x0a
        db "containing random ASCII characters from the following groups:", 0x0a, 0x0a
        db "lower-case letters:  a ──► z", 0x0a
        db "upper-case letters:  A ──► Z", 0x0a
        db "            digits:  0 ──► 9", 0x0a
        db "other printable characters:", 0x0a
        db  0x09, 0x21, 0x22, "#$%&", 0x27, "()*+,-./:;<=>?@[]^_{|}~", 0x0a
        db  0x09, "(the above character list excludes white-space,"
        db  0x09, " backslash and grave)", 0x0a, 0x0a
        db "The generated password(s) must include at least one", 0x0a
        db "(of each of the four groups):", 0x0a
        db "           lower-case letter,", 0x0a
        db "           upper-case letter,", 0x0a
        db "           digit  (numeral),   and", 0x0a
        db "           one  'other'  character.", 0x0a, 0x0a
        db "Created for Rosetta Code.", 0x0a
        db "https:", 0x2f, 0x2f, "rosettacode.org/wiki/Password_generator", 0
chars:
alphau: db "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
endalphau:
        db "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
alphal: db "abcdefghijklmnopqrstuvwxyz"
endalphal:
        db "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
numeri: db "0123456789"
endnumeri:
        db "01234567890123456789012345678901234567890123456789"
specia: db  0x21, 0x22, "#$%&", 0x27, "()*+,-./:;<=>?@[]^_{|}~"
endspecia:
endchars:
default:  db '1', 0
segment readable writable
cmdslot: rq cmdnos
Output:
~$ fasm passgen.asm passgen
flat assembler  version 1.73.30  (16384 kilobytes memory)
4 passes, 1981 bytes.
~$ chmod 755 passgen
~$ ./passgen 8
40xCU%J!
~$ ./passgen 12 4
Ks3{33Z1Kif1
T8rs!y2rGotZ
g5;d/"QBTW7S
oy[YXEB9k7D0
~$ ./passgen 20
d5VL/|%zpuXzQ[QH9C+9
~$ ./passgen 10 4 > passwords.txt
~$ cat passwords.txt
8g8Gv}H<S?
ICf5bl3Hr[
gW5mDp$1ot
4Yjf9n}V2%
~$ 

XPL0

Translation of: Python
string 0;

func In(C, Str);
char C, Str;
[while Str(0) do
    if C = Str(0) then return true else Str:= Str+1;
return false;
];

func New_password(Length, Readable);
int  Length, Readable, I, C;
char Password_chars(100), Punctuation, Visually_similar;
[if Length < 4 then
    [Text(0, "Password length = ");  IntOut(0, Length);
    Text(0, " is too short, minimum length = 4.");
    return "";
    ];
Punctuation:= "!^"#$%&\'()*+,-./:;<=>?@[]^^_{|}~";
Visually_similar:= "Il1O05S2Z";
for I:= 0 to Length-1 do
    [case Ran(4) of
      0: C:= Ran(26) + ^a;
      1: C:= Ran(26) + ^A;
      2: C:= Ran(10) + ^0;
      3: C:= Punctuation(Ran(31))
    other [];
    Password_chars(I):= C;
    if Readable and In(C, Visually_similar) then I:= I-1;
    ];
Password_chars(I):= 0;
return Password_chars;
];

proc Password_generator(Length, Qty, Readable);
int  Length, Qty, Readable, I;
for I:= 0 to Qty-1 do
    [Text(0, New_password(Length, Readable));  CrLf(0)];

[Password_generator(14, 4, true);
 Password_generator( 8, 4, false);
]
Output:
GojA9ep6=3|U,\
U9@p|f'WH7+&TM
8=E7xvm6J9Y([q
zrknig;8Pv+(Va
37s11T68
Ir)wY0P<
54d3o]Ga
95??s]"O

zkl

Put the following code into a file (such as pwdg.zkl):

var pwdLen=10, pwds=1, xclude="";

argh:=Utils.Argh(
L("+xclude","","Don't use these characters",fcn(arg){ xclude=arg }),
L("+len","","Number of characters in password", fcn(arg){ pwdLen=arg.toInt() } ),
L("+num","","Number of passwords to generate", fcn(arg){ pwds=arg.toInt() } ),
);
try{ argh.parse(vm.arglist) }catch{ System.exit(1) }

isd:='wrap(w){ w.pump(String) - xclude }; // iterator to String
g1,g2,g3 := isd(["a".."z"]), isd(["A".."Z"]), isd(["0".."9"]);
g4:="!\"#$%&'()*+,-./:;<=>?@[]^_{|}~" - xclude;
all:=String(g1,g2,g3,g4);
fcn rnd(s){ s[(0).random(s.len())] }  // pick a random character from s
    // generate random characters of filler needed to complete password
fill:=(pwdLen-4).pump.fp(String,rnd.fp(all)); // a deferred/pending calculation

do(numPwds){
   // Data is byte bucket (and editor). I can shuffle a Data but not a String.
   pwd:=T(g1,g2,g3,g4).pump(Data,rnd); // 1 from each of these into a Data
   pwd.extend(fill()).shuffle().text.println();
}

This is a command line program so output can be redirected.

Output:
$ zkl pwdg.zkl -?
Unknown option: ?
Options:
  --len <arg>: Number of characters in password
  --num <arg>: Number of passwords to generate
  --xclude <arg>: Don't use these characters

$ zkl pwdg.zkl --len 10 --xclude "Il1 O0 5S 2Z" --num 5
xyo9p$T]L8
D6}KeDYVq6
4<?BCWpRLj
4~x_46-Tqi
*:XE3G@myQ