Link to home
Start Free TrialLog in
Avatar of BBDIT
BBDIT

asked on

Automatically change ownership of a file?

We have a directory that houses all our user home folders. This directory/drive has quotas enabled. The problem arises when we have a non-interactive account that is used for placing files into users' directories. I would like those files' ownership to change from the non-interactive account to the account for the user whose folder the file is placed in.

Is there a way to do this automatically without me having to go periodically to each folder and taking ownership of all child objects? It's skewing our quotas.

This is on a 2008 r2 server (64bit).
Avatar of vop
vop

Files which are copied from one location to another assume the ownership of the user who did the copying, so a nightly batch copy to another directory and then deleting the source files would be one way of achieving this.

There's also subinacl, downloadable from:

http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=23510

This includes a \setowner switch.

Possibly even more useful! !  Using ICACLS, which is provided with Vista and Server 2003

ICACLS "X:\Home Directories\%userDir%" /setowner "MYDOMAIN\%userDir%" /T

or, using the utility from my previous posting:

SUBINACL /subdirectories "X:\Home Directories\%userDir%" /setowner "MYDOMAIN\%userDir%"

Might need some tweaking using a test directory.

SUBINACL /help /full    gives a verbose help screen.

Avatar of BBDIT

ASKER

Hmm..those are possibles - but they lead to manual intervention. I guess I can live with that if I can script it out, hopefully into one script to handle all my user home folders - which is going to turn this into a scripting question.

Using the dir command I am able to scan a folder (with subdirectories for owners matching a certain string. eg: scanninguser --- dir /a /q /s |find /i "scanninguser")

What I would then want to do is change the owner on the returned files to be that of the user who owns the parent directory. Doing this one at a time is easier, but not practical for time involved.

So... I have a directory that contains 70 subdirectories, one for each user and named according to their username. I need a script that I can run that will do:

1 - Scan the list of directories, somehow saving variables for each directory name (so I can refer to them later in the script, something like %userdirectory%)
2 - Scan the contents of each directory looking for files where the owner is 'scanninguser'. Somehow logging those files as another variable
3 - Modify those files by running subinacl or such and specifying DOMAIN\%userdirectory% as the new owner (as the user home folders are the same name as the user accounts) for each of the files found in step 2

Can this be done?

Sometimes the contents of the home drive changes as new staff are hired or old staff are terminated. I would hate to have to update the script everytime, which is why the need for variables comes into play. Unfortunately I don't know scripting well enough to figure this out on my own =\  Any help would be greatly appreciated.

Avatar of BBDIT

ASKER

Meh - that dir command loses all path information..so scratch that . Back to the drawing board.
Avatar of BBDIT

ASKER

subinacl is the way to go, and I can nix the part about finding files belonging to a certain user, I can just force all files to be set to a given owner.

However I need a way to have it automatically enter each user directory in my parent home folder and then change all the permissiosn to be for that user.

The basic line is :

subinacl /subdirectories "H:\<username>\inc scans\*.*" /setowner=DOMAIN\<username>

That username variable is different for each user, obviously.
Avatar of Qlemo
for /D %%D in (H:\*) do subinacl /subdirectories "%%D\inc scans\*.*" /setowner=DOMAIN\%%~nD

Open in new window

Will go thru the top-level folders of H:, and use the folder name as user name. That works in 99% of cases. For 100%, we really would need to get the owner name, and then reapply that.
Avatar of BBDIT

ASKER

Qlemo: Well the owner name should equal the directory name. I've made dirs for each of my users and it matches whatever their logon name is. I'll test this today and post back. Thanks!
Avatar of BBDIT

ASKER

Ok this line seems to work for me:

for /D %D in (*) do subinacl /subdirectories "%D\Inc Scans\*.*" /setowner=DOMAIN\%D

(I have to add another % as shown in your comment when I use it in the batch file, but from a command prompt this command works as is)

BUT! There is one gotcha. This resets ownership to the given user for *all* files, even ones they already own. This could lead into a lengthy process as opposed to just executing the command on a smaller list of files.

Is there a way to have it only do this on files the user does NOT own? Or if that complicating the matter too much?
You are right about the difference between %% and %. I assumed to wanted to execute in a batch file.

Following options:
a) You can try if icacls, as recommended in http:#a37297745, is faster

b) Else we have to go thru each single folder ourselfs, and get all files not owned by the user. That will slow down the process, but might still be faster as the brute force subinacl / icacls. But the solution needs a lot of checks. And it needs to be in a batch file, because I had to break it down to subroutines.
@echo off
for /D %%U in (H:\*) do call :setown "%%U\inc scans\" DOMAIN\%%~nU

exit /b

:setown   path user
set usr=%2

for /R "%1" %%D in (.) do (
dir %%~fD /q /-c | ^
findstr /v /c:"Directory of" /c:"Volume " /c:" bytes" /c:"<DIR>" | ^
find /i  " %usr:~,23%" | ^
for /F "tokens=4*" %%F in ('more') do call :setownfile "%%~fD" "%%F%%G" %usr%
)

exit /b

:setownfile  path user+filename user
set d=%1
set f=%2
set f=%f:~23,%
set usr=%3

subinacl "%d%\%f%" /setowner=%usr%

exit /b

Open in new window

Avatar of BBDIT

ASKER

Qlemo:

Thanks so much for your time! I do want to execute in batch file when I have it finalized. I simply was doing testing from the command line which is why the single % in my line.

My users are all in the format of <firstname>.<lastname> such as test.user. I found that in line 2, I had to remove the ~n in order to have the full, correct name used. Will this information change anything else in the script (such as line 10 or 13 where you use ~f)?

Would you mind clarifying a couple of things for me?

I start to get confused at line 12. What is contained within %usr:~,23% and/or where is it defined? Could you explain what is line 13 doing?

Lastly, on lines 6 and 18, are the 'path user' and 'path user+filename user' sections ignored by the script or are they relevant somehow?

Thanks again!

~f will result in the fully expanded    drive:path\file.ext    string, so it does not matter whether you have dots in the name or not (for that part). For other parts, like ~n or ~x, it is important to know.

About line 13:
%usr% is defined in line 7 as the second argument (%2) provided with the call (in line 2).
%usr:~,23% will cut off the first 23 characters. That is necessary because dir /Q produces a columned output, where the owner name column is exactly 23 chars wide, and the file name might be appended directly to it without any delimiter. So we will have to find the columns for owner and file name ourself.
While writing that, I realize my code has a flaw. Please replace line 13:
for /F "tokens=3*" %%F in ('more') do call :setownfile "%%~fD" "%%G" %usr%

Open in new window

That will make sure owner and file name are not separated (and spaces removed) by the FOR, but are provided as a string (to be precise, the whole line starting with the owner name will be in %%G).
FOR /F "tokens=3*" %%F     will count the "fields" or "columns" separated by spaces or tab, then only take the 3rd (into %%F) and anything else behind the 3rd into the next var, which is %%G.
| FOR /F ... ('more')    takes the input from the pipeline (the previous commands), and process them line by line.
I hope that explained it sufficiently.

The additional text in line 6 and 18 are comments, though they might not look like that. You can write anything after a label, as long as it is separated from the label name by at least one space or tab (and some other delimiters).
So if you would leave them out, nothing would change to the script.
Avatar of BBDIT

ASKER

Awesome.

Thanks man. Lastly - is there a way to log the result of this? Maybe output to a text file the results (showing the list of files changed or something). Is it just a matter of putting >> log.txt (or such) after each command where something is executing?
Avatar of BBDIT

ASKER

Doesn't appear to work.

I'm attaching the batch file I'm using, as well as a screenshot of out the output I'm getting.

I'm doing this in a test directory (c:\test) with only 1 user dir within it (test.user). At the top of the output screenshot is 2 dir commands showing there are contents in the directory.

Any thoughts?


testingbat.txt
Capture.JPG
Avatar of BBDIT

ASKER

oops..forgot to show the directory listings. Attached.
Capture1.JPG
Maybe I should write the code in a way it works? It does not make sense to change the owner of files which are already set correct, and leave the other ones unchanged :(.
My line 12 needs to be
find /i /v  " %usr:~,23%" | ^

Open in new window

Avatar of BBDIT

ASKER

output is still off.. See attached.

Builtin\Administrators is current owner. Should change to BBD\test.user.

The path and file name are being seperated somehow instead of combined. Also not sure about the 'invalid attempt to call batch label..." error.


Capture.JPG
Use this one. The FOR /F ... with pipe and more does not work well - cmd.exe behaves very strange in that case most of the time, I didn't remember that. So I had to rewrite some code. And I could not get subinacl to change my files at all, so I switched to icacls, which is faster anyway.
@echo off
setlocal EnableDelayedExpansion

for /D %%U in (H:\*) do call :setown "%%U\inc scans\" "DOMAIN\%%~nU"

exit /b

:setown   path user
set usr=%~2

for /R "%~1" %%D in (.) do ^
for /F "tokens=3*" %%F in ('
dir "%%~fD" /q /-c ^| ^
findstr /v /c:"Directory of" /c:"Volume " /c:" bytes" /c:"<DIR>" ^| ^
find /i /v  " %usr:~,23%" ') do (
  set d=%%~fD
  set f=%%G
  set f=!f:~23!
  icacls "!d!\!f!" /setowner "%usr%"
)
)
exit /b

Open in new window

Avatar of BBDIT

ASKER

Thanks again Qlemo!

Not working quite yet though, though this worked better.

Lines 18 and 19 - are those supposed to be exclamation marks (!) or should they be percents (%) for the variable references?

Also - %G is being set as: 0 BUILTIN\Administrators <filename>.<fileextension> should this not only be the filename.extension (ie: test.txt)?

Attached is the output I'm getting.


Capture.JPG
! instead of % is used for Delayed Expansion - that is, vars are expanded when they are executed (instead of parsed). Since code in the same line is parsed at once, something like
   set x=1& echo %x%
does not work. If DE is enabled,
   set x=1& echo !x!
does. DE is enabled with that setlocal command at the very beginning of the script.
Code in parens is treated as a single line, so the same applies here.

The message "... no mapping ..." is because your user does not exist, but I reckon that is intentionally.

You are correct about %%G being wrong. This is because I have Military Time, and your am/pm stuff adds another "column". You should be fine by changing line 12, according to this:
@echo off
setlocal EnableDelayedExpansion

for /D %%U in (H:\*) do call :setown "%%U\inc scans\" "DOMAIN\%%~nU"

exit /b

:setown   path user
set usr=%~2

for /R "%~1" %%D in (.) do ^
for /F "tokens=4*" %%F in ('
dir "%%~fD" /q /-c ^| ^
findstr /v /c:"Directory of" /c:"Volume " /c:" bytes" /c:"<DIR>" ^| ^
find /i /v  " %usr:~,23%" ') do (
  set d=%%~fD
  set f=%%G
  set f=!f:~23!
  icacls "!d!\!f!" /setowner "%usr%"
)
)
exit /b

Open in new window


And please do me a favour: Do not post that output as screenshot, but put it into a code tag. That is much easier to read, and I can cut & waste stuff ;-).
Avatar of BBDIT

ASKER

Ok tried again. changed the 3* to 4 - seems to pull the information in correctly now. Only thing I'm not sure about is right below the icacls line. There is no leading quotes around the file path (so of course you get the 'syntax is incorrect' error). (lines 56 and 57 of my snippet.

I can't seem to figure out how to get it so it includes that leading quote. Ideas?

Trying the code embed.... increasing the point value of this question too due to the amount of 'tweaking' =)

 
c:\>testing.bat

c:\>setlocal EnableDelayedExpansion

c:\>for / %U in (C:\test\*) do call :setown "%U\incoming scans\" "BBD\%~nxU"

c:\>call :setown "C:\test\test\incoming scans\" "BBD\test"

c:\>set usr=BBD\test

c:\>for /R "C:\test\test\incoming scans\" %D in (.) do for /F "tokens=4*" %F in (' dir "%~fD" /q /-c | findstr /v /c:"Directory of" /c:"Volume " /c:" bytes" /c:"<DIR>" | find /i /v " BBD\test" ') do (
set d="%~fD
 set f=%G"
 set f=!f:~23!
 icacls !d!\!f!" /setowner "BBD\test"
)

c:\>for /F "tokens=4*" %F in (' dir "C:\test\test\Incoming Scans" /q /-c | findstr /v /c:"Directory of" /c:"Volume " /c:" bytes" /c:"<DIR>" | find /i /v " BBD\test" ') do (
set d="C:\test\test\Incoming Scans
 set f=%G"
 set f=!f:~23!
 icacls !d!\!f!" /setowner "BBD\test"
)

c:\>(
set d="C:\test\test\Incoming Scans
 set f=BBD\jenny.kellett      this should change.txt"
 set f=!f:~23!
 icacls !d!\!f!" /setowner "BBD\test"
)
C:\test\test\Incoming Scans\this should change.txt": The filename, directory name, or volume label syntax is incorrect.
Successfully processed 0 files; Failed processing 1 files

c:\>(
set d="C:\test\test\Incoming Scans
 set f=BBD\jenny.kellett      thistoo.txt"
 set f=!f:~23!
 icacls !d!\!f!" /setowner "BBD\test"
)
C:\test\test\Incoming Scans\thistoo.txt": The filename, directory name, or volume label syntax is incorrect.
Successfully processed 0 files; Failed processing 1 files

c:\>for /F "tokens=4*" %F in (' dir "C:\test\test\Incoming Scans\fasf" /q /-c | findstr /v /c:"Directory of" /c:"Volume " /c:" bytes" /c:"<DIR>" | find /i /v " BBD\test" ') do (
set d="C:\test\test\Incoming Scans\fasf
 set f=%G"
 set f=!f:~23!
 icacls !d!\!f!" /setowner "BBD\test"
)

c:\>(
set d="C:\test\test\Incoming Scans\fasf
 set f=BBD\jenny.kellett      should change.txt"
 set f=!f:~23!
 icacls !d!\!f!" /setowner "BBD\test"
)
C:\test\test\Incoming Scans\fasf\should change.txt": The filename, directory name, or volume label syntax is incorrect.
Successfully processed 0 files; Failed processing 1 files

c:\>exit /b

c:\>exit /b

c:\>

Open in new window

Avatar of BBDIT

ASKER

Also of note, in my previous code snip - line 5 .. the batch file has 'for /D %%U....' , but when it runs it drops the D - is that a problem?
That /D => / effect is strange, but it is only an issue with the echoing of commands.

Is that output really from my code? I tested it on my system, with similar folders, and it worked great.
My code line 19 (the icacls) has all necessary quotes, and the SET lines above it must not have quotes.
Avatar of BBDIT

ASKER

ya ..it's from your code. Well, with minor tweaks for my folders/usernames.

I'll add the code exactly as it sits in the batch file :
@echo on
setlocal EnableDelayedExpansion

for /D %%U in (C:\test\*) do call :setown "%%U\incoming scans\" "BBD\%%~nxU"

exit /b

:setown   path user
set usr=%~2

for /R "%~1" %%D in (.) do ^
for /F "tokens=4*" %%F in ('
dir "%%~fD" /q /-c ^| ^
findstr /v /c:"Directory of" /c:"Volume " /c:" bytes" /c:"<DIR>" ^| ^
find /i /v  " %usr:~,23%" ') do (
  set d="%%~fD
  set f=%%G"
  set f=!f:~23!
  icacls !d!\!f!" /setowner "%usr%"
)
)
exit /b

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Qlemo
Qlemo
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of BBDIT

ASKER

Thought for sure I tested without and it didnt' work. Anyway - you are indeed correct sir. This appears to work. It changes all files (but not directories - which is fine, that's great for my environment) in the directories of my users.

Qlemo, thanks so much for all your time (and this was considerable) and your patience. You are exactly what this site needs. Thanks again!!