change Oracle user account status from EXPIRE(GRACE) to OPEN - oracle

After getting the message Your password will be expired with in 7 days, I changed the password expire days of the default profile to UNLIMITED. But the account status of some users are still remaining in EXPIRE(GRACE).
Any way to change the Oracle user account status from EXPIRE(GRACE) to OPEN without resetting the password?

No, you cannot directly change an account status from EXPIRE(GRACE) to OPEN without resetting the password.
The documentation says:
If you cause a database user's password to expire with PASSWORD
EXPIRE, then the user (or the DBA) must change the password before
attempting to log into the database following the expiration.
However, you can indirectly change the status to OPEN by resetting the user's password hash to the existing value. Unfortunately, setting the password hash to itself has the following complications, and almost every other solution misses at least one of these issues:
Different versions of Oracle use different types of hashes.
The user's profile may prevent re-using passwords.
Profile limits can be changed, but we have to change the values back at the end.
Profile values are not trivial because if the value is DEFAULT, that is a pointer to the DEFAULT profile's value. We may need to recursively check the profile.
The following, ridiculously large PL/SQL block, should handle all of those cases. It should reset any account to OPEN, with the same password hash, regardless of Oracle version or profile settings. And the profile will be changed back to the original limits.
--Purpose: Change a user from EXPIRED to OPEN by setting a user's password to the same value.
--This PL/SQL block requires elevated privileges and should be run as SYS.
--This task is difficult because we need to temporarily change profiles to avoid
-- errors like "ORA-28007: the password cannot be reused".
--
--How to use: Run as SYS in SQL*Plus and enter the username when prompted.
-- If using another IDE, manually replace the variable two lines below.
declare
v_username varchar2(128) := trim(upper('&USERNAME'));
--Do not change anything below this line.
v_profile varchar2(128);
v_old_password_reuse_time varchar2(128);
v_uses_default_for_time varchar2(3);
v_old_password_reuse_max varchar2(128);
v_uses_default_for_max varchar2(3);
v_alter_user_sql varchar2(4000);
begin
--Get user's profile information.
--(This is tricky because there could be an indirection to the DEFAULT profile.
select
profile,
case when user_password_reuse_time = 'DEFAULT' then default_password_reuse_time else user_password_reuse_time end password_reuse_time,
case when user_password_reuse_time = 'DEFAULT' then 'Yes' else 'No' end uses_default_for_time,
case when user_password_reuse_max = 'DEFAULT' then default_password_reuse_max else user_password_reuse_max end password_reuse_max,
case when user_password_reuse_max = 'DEFAULT' then 'Yes' else 'No' end uses_default_for_max
into v_profile, v_old_password_reuse_time, v_uses_default_for_time, v_old_password_reuse_max, v_uses_default_for_max
from
(
--User's profile information.
select
dba_profiles.profile,
max(case when resource_name = 'PASSWORD_REUSE_TIME' then limit else null end) user_password_reuse_time,
max(case when resource_name = 'PASSWORD_REUSE_MAX' then limit else null end) user_password_reuse_max
from dba_profiles
join dba_users
on dba_profiles.profile = dba_users.profile
where username = v_username
group by dba_profiles.profile
) users_profile
cross join
(
--Default profile information.
select
max(case when resource_name = 'PASSWORD_REUSE_TIME' then limit else null end) default_password_reuse_time,
max(case when resource_name = 'PASSWORD_REUSE_MAX' then limit else null end) default_password_reuse_max
from dba_profiles
where profile = 'DEFAULT'
) default_profile;
--Get user's password information.
select
'alter user '||name||' identified by values '''||
spare4 || case when password is not null then ';' else null end || password ||
''''
into v_alter_user_sql
from sys.user$
where name = v_username;
--Change profile limits, if necessary.
if v_old_password_reuse_time <> 'UNLIMITED' then
execute immediate 'alter profile '||v_profile||' limit password_reuse_time unlimited';
end if;
if v_old_password_reuse_max <> 'UNLIMITED' then
execute immediate 'alter profile '||v_profile||' limit password_reuse_max unlimited';
end if;
--Change the user's password.
execute immediate v_alter_user_sql;
--Change the profile limits back, if necessary.
if v_old_password_reuse_time <> 'UNLIMITED' then
if v_uses_default_for_time = 'Yes' then
execute immediate 'alter profile '||v_profile||' limit password_reuse_time default';
else
execute immediate 'alter profile '||v_profile||' limit password_reuse_time '||v_old_password_reuse_time;
end if;
end if;
if v_old_password_reuse_max <> 'UNLIMITED' then
if v_uses_default_for_max = 'Yes' then
execute immediate 'alter profile '||v_profile||' limit password_reuse_max default';
else
execute immediate 'alter profile '||v_profile||' limit password_reuse_max '||v_old_password_reuse_max;
end if;
end if;
end;
/

Compilation from jonearles' answer, http://kishantha.blogspot.com/2010/03/oracle-enterprise-manager-console.html and http://blog.flimatech.com/2011/07/17/changing-oracle-password-in-11g-using-alter-user-identified-by-values/ (Oracle 11g):
To stop this happening in the future do the following.
Login to sqlplus as sysdba -> sqlplus "/as sysdba"
Execute ->ALTER PROFILE DEFAULT LIMIT FAILED_LOGIN_ATTEMPTS UNLIMITED PASSWORD_LIFE_TIME UNLIMITED;
To reset users' status, run the query:
select
'alter user ' || su.name || ' identified by values'
|| ' ''' || spare4 || ';' || su.password || ''';'
from sys.user$ su
join dba_users du on ACCOUNT_STATUS like 'EXPIRED%' and su.name = du.username;
and execute some or all of the result set.

set long 9999999
set lin 400
select DBMS_METADATA.GET_DDL('USER','YOUR_USER_NAME') from dual;
This will output something like this:
SQL> select DBMS_METADATA.GET_DDL('USER','WILIAM') from dual;
DBMS_METADATA.GET_DDL('USER','WILIAM')
--------------------------------------------------------------------------------
CREATE USER "WILIAM" IDENTIFIED BY VALUES 'S:6680C1468F5F3B36B726CE7620F
FD9657F0E0E49AE56AAACE847BA368CEB;120F24A4C2554B4F'
DEFAULT TABLESPACE "USER"
TEMPORARY TABLESPACE "TEMP"
PASSWORD EXPIRE
Just use the first piece of that with alter user instead:
ALTER USER "WILIAM" IDENTIFIED BY VALUES 'S:6680C1468F5F3B36B726CE7620F
FD9657F0E0E49AE56AAACE847BA368CEB;120F24A4C2554B4F';
This will put the account back in to OPEN status without changing the password (as long as you cut and paste correctly the hash value from the output of DBMS_METADATA.GET_DDL) and you don't even need to know what the password is.

In case you know the password of that user, or you would like to guess it, do the following:
connect user/password
If this command connects successufully, you will see the message "connected", otherwise you'd see an error message. If you are then successufull logging, that means that you know the password.
In that case, just do:
alter user NAME_OF_THE_USER identified by OLD_PASSWORD;
and this will reset the password to the same password as before and also reset the account_status for that user.

Step-1 Need to find user details by using below query
SQL> select username, account_status from dba_users where username='BOB';
USERNAME ACCOUNT_STATUS
------------------------------ --------------------------------
BOB EXPIRED
Step-2 Get users password by using below query.
SQL>SELECT 'ALTER USER '|| name ||' IDENTIFIED BY VALUES '''|| spare4 ||';'|| password ||''';' FROM sys.user$ WHERE name='BOB';
ALTER USER BOB IDENTIFIED BY VALUES 'S:9BDD17811E21EFEDFB1403AAB1DD86AB481E;T:602E36430C0D8DF7E1E453;2F9933095143F432';
Step -3 Run Above alter query
SQL> ALTER USER BOB IDENTIFIED BY VALUES 'S:9BDD17811E21EFEDFB1403AAB1DD86AB481E;T:602E36430C0D8DF7E1E453;2F9933095143F432';
User altered.
Step-4 :Check users account status
SQL> select username, account_status from dba_users where username='BOB';
USERNAME ACCOUNT_STATUS
------------------------------ --------------------------------
BOB OPEN

PART I (FIND IF USER EXISTS)
--could check with a system type account e.g.SYS
SQL> select username, account_status from dba_users where username='BOB';
SQL> select username, account_status from dba_users where username like 'BOB%';
SQL> select username, account_status from dba_users where like '%BOB%';
PART II Changing the account properties
SQL> ALTER user [username] account UNLOCK; --unlocks the account it it was locked
SQL> Alter user [username] IDENTIFIED BY "password"; --would change the password for user

SQL> ALTER user [username] account UNLOCK; --unlocks the account it it was locked
SQL> Alter user [username] IDENTIFIED BY "password"; --would change the password for user
This one is working for me.

Related

PL/SQL While/For Loop

I'm a DBA, just trying to write a piece of code to capture user privileges in Oracle and write to a table. The below code works ok for one user, but if the ELSE part has multiple users I get the error: "ORA-01422: exact fetch returns more than requested number of rows". Makes sense, I realise I need a for/while loop to handle multiple rows, can someone help me with that?
'''
declare
altersystem varchar2(550);
altersystemconcat varchar2(550);
begin
select grantee
into altersystem
from dba_sys_privs
where privilege = 'ALTER SYSTEM'
and grantee not in ('SYS', 'SYSTEM');
if altersystem = 'No rows selected'
then
insert into catch
values
('900'
,'No custom users with the Alter System privilege.');
else
select concat('The following user/role has the Alter System privilege, revoke if not required: '
,altersystem)
into altersystemconcat
from dual;
insert into catch
values
('100'
,altersystemconcat);
end if;
end;
/
'''
An select ... INTO ... requires exactly one row to be returned, otherwise you get an exception. Usually you have to loop over a cursor, but you can do it even in a single command like this:
BEGIN
INSERT INTO catch
SELECT 900, 'The following user/role has the Alter System privilege, revoke if not required: '||grantee
FROM dba_sys_privs
WHERE PRIVILEGE = 'ALTER SYSTEM'
AND grantee NOT IN ('SYS', 'SYSTEM');
IF SQL%ROWCOUNT = 0 THEN
INSERT INTO catch VALUES (100, 'No custom users with the Alter System privilege.');
END IF;
END;
Umm ... no, ELSE's SELECT doesn't return too-many-rows. It selects from DUAL which has only 1 row so ...
I suspect it is the first statement, select grantee into altersystem. If there's more than one user that satisfies those conditions, you can't put them all into the variable which is declared as varchar2. Therefore, yes - a loop might help, it is simple enough.
But, why? Why don't you simply insert all those offenders using single insert? Something like this:
INSERT INTO catch
SELECT '000', grantee
FROM dba_sys_privs
WHERE privilege = 'ALTER SYSTEM'
AND grantee NOT IN ('SYS', 'SYSTEM');
This can be done in a single SQL statement - no need for PL/SQL (unless you need it as a stored procedure):
INSERT INTO catch (col1, col2) -- change col1 and col2 to the correct column_names in catch that you're inserting into
WITH no_users AS (SELECT 100 no_user_present_id, 'No custom users with the Alter System privilege.' no_user_text FROM dual),
users_there AS (SELECT 900 user_present_id, 'The following user/role has the Alter System privilege, revoke if not required: '||grantee user_there_text
FROM dba_sys_privs
WHERE PRIVILEGE = 'ALTER SYSTEM'
AND grantee NOT IN ('SYS', 'SYSTEM'))
SELECT COALESCE(ut.user_present_id, nu.no_user_present_id) ID,
COALESCE(ut.user_there_text, nu.no_user_text) text
FROM no_users nu
LEFT OUTER JOIN users_there ut ON 1 = 1;
This works by using an outer join so that the row for when there's no user is always returned. If there are no users present, the row that is returned is the default row. If there are users that have the specified grant, you will get the rows for those users returned.
Using the listagg function you can concatenate the resulting string.
Commented out the insert statements as I don't have the catch table. Printing to output instead.
Use an exception handler in case no rows found.
declare
altersystem varchar2(550);
altersystemconcat varchar2(550);
begin
select listagg(grantee, ', ') within group(order by grantee) "Grantee"
into altersystem
from dba_sys_privs
where privilege = 'ALTER SYSTEM'
and grantee not in ('SYS', 'SYSTEM');
dbms_output.put_line('The following user/role has the Alter System privilege, revoke if not required: ' || altersystem);
/*
insert into catch
values
('100'
,'The following user/role has the Alter System privilege, revoke if not required: ' || altersystem);
*/
exception
when no_data_found then
dbms_output.put_line('No custom users with the Alter System privilege.');
/*
insert into catch
values
('900'
,'No custom users with the Alter System privilege.');
*/
end;
/

How to update a VERIFY_PASSWORD_FUNCTION in oracle for users to retain his password for 1 day at least before change/alter it

It a one of requirement where the client needs there Oracle users do not change his password very soon, so they need to retain at least one day before altering it. So it can not be changed on the same day, where we have to update VERIFY_PASSWORD_FUNCTION code to set a limit minimum password age 1 day.
Append Below Code in "VERIFY_PASSWORD_FUNCTION" Function:
CREATE OR REPLACE FUNCTION "SYS"."VERIFY_PASSWORD_FUNCTION"
(username varchar2,
password varchar2,
old_password varchar2)
RETURN boolean IS
last_change sys.user$.ptime%type;
minimum_age number :=1;
userexist integer;
begin
-- Set minimum password age
select count(*) into userexist from sys.user$ where name=username;
if (userexist != 0) then
select ptime into last_change from sys.user$ where name=username;
if sysdate - last_change < minimum_age then
raise_application_error(-20010, 'Password changed too soon');
END IF;
end if;
end;
/
From the above code you have to append only variables and logic.
Here is A Test Case:
SQL> create user TEST11 identified by asdfhe#24HyrE profile USERS;
User Created.
SQL> alter user test11 identified by asdfhe#24HyrWW;
alter user test11 identified by asdfhe#24HyrWW
*
ERROR at line 1:
ORA-28003: password verification for the specified password failed
ORA-20010: Password changed too soon
SQL>
SQL> select name,ptime from user$ where name='TEST11';
NAME PTIME
------------------------------ ---------
TEST11 08-NOV-18
SQL> update user$ set ptime='03-Nov-18' where name='TEST11';
1 row updated.
SQL> select name,ptime from user$ where name='TEST11';
NAME PTIME
------------------------------ ---------
TEST11 03-NOV-18
SQL> commit;
Commit complete.
SQL> alter user test11 identified by asdfhe#24HyrWW;
User altered.
SQL>
Since we can not change the password within same day so we've updated ptime value to verify and tried again to alter password for Test11 user.

Issues with user/system oracle role access and permissions

I am having a bit of an odd issue when it comes to oracle roles and my schema creation code, I will do my best to describe my problem below:
On schema create a role is created using the schema name provided.
EXECUTE IMMEDIATE 'CREATE ROLE ' || USER || 'ADMIN_R';
This role is then granted to specific users associated with that schema.
DECLARE
V_ROLE_NAME CONSTANT VARCHAR2(30) := USER || 'ADMIN_R';
CURSOR C_ADMIN_USERS IS
SELECT USERNAME FROM DBUSERS WHERE ROLE = 'ADMINISTRATION';
BEGIN
FOR REC IN C_ADMIN_USERS
LOOP
EXECUTE IMMEDIATE 'GRANT ' || V_ROLE_NAME || ' TO ' || REC.USERNAME || ' WITH ADMIN OPTION';
END LOOP;
END;
Users with this role have access to a special administration package.
EXECUTE IMMEDIATE 'GRANT EXECUTE ON P_ADMINISTRATION TO ' || USER || 'ADMIN_R';
The problem is When I drop the schema it does not drop this role (belongs to oracle), so when I recreate this schema the whole process fails because this role already exists. I also can't grant access to this role without logging into the system users which I want to avoid. The simple solution would be to just drop it, but my concern in that instance is that the DBA has been using that role to grant access to additional users and potentially additional packages, which would all be lost if we just arbitrarily drop the role to recreate it.
Any assistance would be greatly appreciated.
You could surround your role create with something like this:
SELECT COUNT(*)
INTO v_count
FROM DBA_ROLES
WHERE ROLE = USER || 'ADMIN_R';
IF v_count = 0 THEN
--grant your roles
END IF;
You can grant the same privilege as many times as you like.
you can drop the role before create
declare
i int;
begin
select count(*) into i
from dba_roles where role = USER||'ADMIN_R';
if (0 != i) then
execute immediate 'drop role '||USER||'ADMIN_R';
dbms_output.put_line('Role ' ||USER||'ADMIN_R has been dropped');
end if;
execute immediate 'create role '||USER||'ADMIN_R';
dbms_output.put_line('Role ' ||USER||'ADMIN_R has been created');
end;
1st try:
Role SCMADMIN_R has been created
2nd try:
Role SCMADMIN_R has been dropped
Role SCMADMIN_R has been created

Procedure being created but doesn't work

DECLARE
BEGIN
FOR s IN ( SELECT first_name
FROM EA_marketing_table
WHERE town = 'LONDON'
)
LOOP
EXECUTE IMMEDIATE 'CREATE USER ' ||(s.first_name)|| ' IDENTIFIED BY LOL';
dbms_output.put_line (s.first_name || ' IDENTIFIED BY LOL');
END LOOP;
END;
/
I am trying to create a user and the code above lets me create a user but when I try to create a procedure it wont work.
This is the new code
CREATE OR REPLACE PROCEDURE proc_it_development AS
first_name VARCHAR2 (25);
BEGIN
FOR r IN ( SELECT first_name
FROM EA_marketing_table
WHERE town = 'lONDON ')
LOOP
EXECUTE IMMEDIATE 'CREATE USER '||(r.first_name)|| ' IDENTIFIED BY POOP ';
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND THEN dbms_output.put_line ('r SELECT...INTO did not return any row.');
END;
/
any help please?
:)
Roles are not enabled in procedures/packages so you need to get the privilege granted to your user directly. Most likely you are connecting through a user that has been given the CREATE USER privilege via a role (eg: the DBA role?)
To see what you can do in a procedure, you can disable the active roles for your current session:
set role none
then try your first code block. If it works, it will also work in a procedure.
To create a new schema with a procedure you will need the privilege granted directly to your schema:
GRANT CREATE USER TO <your_schema>;
You should enclose the password in double-quotes, in Oracle 11 passwords are case-sensitive by default. Then you only create a user without any privilege, i.e.CREATE SESSION Privilege is missing.

Dropping connected users in Oracle database

I want to drop some users in Oracle DB using sqlplus but I am getting error:
SQL> DROP USER test CASCADE;
DROP USER test CASCADE
*
ERROR at line 1:
ORA-01940: cannot drop a user that is currently connected
I followed the link in SO to find out the sessions - Dropping a connected user from an Oracle 10g database schema
But when I ran the command I am not getting any results:
SQL> select sid,serial# from v$session where username = 'test';
no rows selected
Please help me how to drop users in this case.
Users are all capitals in v$session (and data dictionary views). If you match with capitals you should find your session to kill.
SELECT s.sid, s.serial#, s.status, p.spid
FROM v$session s, v$process p
WHERE s.username = 'TEST' --<<<--
AND p.addr(+) = s.paddr
/
Pass actual SID and SERIAL# values for user TEST then drop user...:
ALTER SYSTEM KILL SESSION '<SID>, <SERIAL>'
/
Solution :
login as sysdaba:
sqlplus / as sysdba
then:
sql>Shutdown immediate;
sql>startup restrict;
sql>drop user TEST cascade;
If you want to re-activate DB normally either reset the server or :
sql>Shutdown immediate;
sql>startup;
:)
Issue has been fixed using below procedure :
DECLARE
v_user_exists NUMBER;
user_name CONSTANT varchar2(20) := 'SCOTT';
BEGIN
LOOP
FOR c IN (SELECT s.sid, s.serial# FROM v$session s WHERE upper(s.username) = user_name)
LOOP
EXECUTE IMMEDIATE
'alter system kill session ''' || c.sid || ',' || c.serial# || ''' IMMEDIATE';
END LOOP;
BEGIN
EXECUTE IMMEDIATE 'drop user ' || user_name || ' cascade';
EXCEPTION WHEN OTHERS THEN
IF (SQLCODE = -1940) THEN
NULL;
ELSE
RAISE;
END IF;
END;
BEGIN
SELECT COUNT(*) INTO v_user_exists FROM dba_users WHERE username = user_name;
EXIT WHEN v_user_exists = 0;
END;
END LOOP;
END;
/
Do a query:
SELECT * FROM v$session s;
Find your user and do the next query (with appropriate parameters):
ALTER SYSTEM KILL SESSION '<SID>, <SERIAL>';
If you use RAC then you need to use GV$* views instead V$*.
Try to find your session by
select * from gv$session where username = 'test';
and then you can kill the session by
alter system kill session 'sid, serial#, #inst_id' immediate;
This can be as simple as:
SQL> ALTER SYSTEM ENABLE RESTRICTED SESSION;
SQL> DROP USER test CASCADE;
SQL> ALTER SYSTEM DISABLE RESTRICTED SESSION;
go to services in administrative tools and select oracleserviceSID and restart it
I was trying to follow the flow described here - but haven't luck to completely kill the session.. Then I fond additional step here:
http://wyding.blogspot.com/2013/08/solution-for-ora-01940-cannot-drop-user.html
What I did:
1. select 'alter system kill session ''' || sid || ',' || serial# || ''';' from v$session where username = '<your_schema>'; - as described below.Out put will be something like this:alter system kill session '22,15' immediate;
2. alter system disconnect session '22,15' IMMEDIATE ; - 22-sid, 15-serial - repeat the command for each returned session from previous command
3. Repeat steps 1-2 while select... not return an empty table
4. Call
drop user...
What was missed - call alter system disconnect session '22,15' IMMEDIATE ; for each of session returned by select 'alter system kill session '..
Sometimes Oracle drop user takes long time to execute. In that case user might be connected to the database. Better you can kill user session and drop the user.
SQL> select 'alter system kill session ''' || sid || ',' || serial# || ''' immediate;' from v$session where username ='&USERNAME';
SQL> DROP USER barbie CASCADE;
I had the same problem, Oracle config in default affects letter register. In exact my Scheme_Name was written all Capital letters. You can see your Scheme_Name on "Other Users" tab, if you are using Oracle S
Basically I believe that killing all sessions should be the solution, but...
I found similar discussion - https://community.oracle.com/thread/1054062 to my problem and that was I had no sessions for that users, but I still received the error. I tried also second the best answer:
sql>Shutdown immediate;
sql>startup restrict;
sql>drop user TEST cascade;
What worked for me at the end was to login as the user, drop all tables manually - select for creating drop statements is
select 'drop table ' || TABLE_NAME || ';' from user_tables;
(Needs to be re-run several times because of references)
I have no idea how is that related, I dropped also functions and sequences (because that was all I had in schema)
When I did that and I logged off, I had several sessions in v$session table and when I killed those I was able to drop user.
My DB was still started in restricted mode (not sure if important or not).
Might help someone else.
BTW: my Oracle version is Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
//'SYS' is username from where you wanted to kill session'
SELECT * FROM DBA_TAB_PRIVS WHERE GRANTEE = 'SYS';
**Step 1:**
CREATE OR REPLACE PROCEDURE sys.kill_session(p_sid NUMBER, p_serial NUMBER)
AS
v_user VARCHAR2(30);
BEGIN
SELECT MAX(username)
INTO v_user
FROM v$session
WHERE sid = p_sid
AND serial# = p_serial;
**Step 2**
create or replace procedure kill_session( p_sid in number, p_serial# in number)
is v_count pls_integer;
BEGIN
select count(*) into v_count
from V$session
where username = 'SYS'
and sid = p_sid
and serial# = p_serial# ;
if ( v_count = 1 )
then
execute immediate '
alter system kill session ''' ||
to_char(p_sid,'999999')||','||
to_char(p_serial#,'999999')||'''';
else
raise_application_error( -20001,
'You do not own session ''' ||
p_sid || ',' || p_serial# ||
'''' );
end if;
END;
/
**Step 3**
grant execute on kill_session to SYS;
**Step 4**
select inst_id, sid, serial#, username, action, program, service_name, con_id from gv$session where username like 'FCM_469';
Check there will be no sessions now
**Step 5**
DROP USER USER_345 CASCADE;
Output:User Dropped
Here's how I "automate" Dropping connected users in Oracle database:
# A shell script to Drop a Database Schema, forcing off any Connected Sessions (for example, before an Import)
# Warning! With great power comes great responsibility.
# It is often advisable to take an Export before Dropping a Schema
if [ "$1" = "" ]
then
echo "Which Schema?"
read schema
else
echo "Are you sure? (y/n)"
read reply
[ ! $reply = y ] && return 1
schema=$1
fi
sqlplus / as sysdba <<EOF
set echo on
alter user $schema account lock;
-- Exterminate all sessions!
begin
for x in ( select sid, serial# from v\$session where username=upper('$schema') )
loop
execute immediate ( 'alter system kill session '''|| x.Sid || ',' || x.Serial# || ''' immediate' );
end loop;
dbms_lock.sleep( seconds => 2 ); -- Prevent ORA-01940: cannot drop a user that is currently connected
end;
/
drop user $schema cascade;
quit
EOF

Resources