Assigning fullaccess rights when creating new user-specific Homefolders - powershell

So I have been trying to figure out how to create user-specific home folders and give the user FullAccess rights to his/her own (new) Homefolder. The location of the Homefolders is always the same, so I want to make it work by just changing the names to the correct usernames.
So far I have come up with the following code. I will include the first part which does work, because it might help to understand what I'm aiming at. Also, I'm fairly new at powershell, so apologies for any amateur coding you may find...
###Create a new Homefolder
##Set the user(s) that need a new Homefolder (Use the SamAccountName)
$UserList = "Guest1","Guest2","Guest3"
foreach ($User in $UserList)
{
##Set the properties of the folder
$File = [PSCustomObject]#{
Name = "$User.test"
Path = "C:\Users\ItsMe\Documents\Homefolder test\"
ItemType = "directory"
}
##Create the directory in the specified path
New-Item -Path $File.Path -Name $File.Name -ItemType $File.ItemType
#Test if the folder is successfully created, before moving on.
Test-Path "C:\Users\ItsMe\Documents\Homefolder test\Guest1.test"
#Get the path of the new directory
$DirPath = $("$File.Path\$File.Name")
###Set Acl to assign FullAccess rights
$NewAcl = Get-Acl -Path "$DirPath"
## Set properties
$identity = "$User"
$fileSystemRights = "FullControl"
$type = "Allow"
}
The code goes a little further, but this is where the main error lies.
The output gives me the folders Guest1.test, Guest2.test and Guest3.test in the correct location (the ".test" after the SamAccountName is necessary, as it will be replaced by the Company name in the real script).
After that however, I get the following error a couple times.
Get-Acl : Cannot find drive. A drive with the name '#{Name=Guest1.test; Path=C' does not exist.
The $DirPath variable does not take the right path of the newly created folders. The Test-Path command confirms that the folder is created before the error. By using Write-Host $DirPath I found that it saved the following value:
Write-Host $DirPath
#{Name=Guest3.test; Path=C:\Users\ItsMe\Documents\Homefolder test\; ItemType=directory}.Path\#{Name=Guest3.test; Path=C:\Users\ItsMe\Documents\Homefolder test\; ItemType=directory}.Name
When I run Get-Acl by manually setting the path (that I want the $DirPath variable to be), after the folders have been created, it works like intended:
Get-Acl -Path "C:\Users\ItsMe\Documents\Homefolder test\Guest1.test"
I have tried to take the whole Acl part out of this "foreach" section and create another "foreach" to assign the FullAccess rights for each user, but so far I have not been able to make that work either (It could be the best way, but I just have not figured it out yet).
Any tips on how to make this work will be appreciated. I feel like the current structure might be wrong.

You might try:
$DirPath = $($File.Path\$File.Name)
Also, if you run test-path inside the foreach loop after you create the folder, you’ll know whether it’s now there or not.

Create a separate variable for each value in $File; it’s a hashtable.
I actually don’t know that it’s buying you anything based on the use-case.
ItemType is unchanging; I’d define it above the loop.
I’d build the user’s folder path by concatenating the base to the Username with .test

Related

Powershell Windows in a Domain: how to retrieve actual home directory of renamed user

Over the course of time, our organization has gone through some profile name changs (i.e. when a person marries) and there has not been a standard of also renaming the user's home directory. So we have users like MarySmith whose directories are like C:\USERS\MaryJones. No problem thus far, but now we would like to clean these up to avoid confusion. (MarySmith / MaryJones used here are for illustrative purposes only.) We are beginning to go through some security measures and elimination of this "confusion" plays a part in the process.
So our first step, was to identify the cases where this has taken place. On the Domain Controllers, we issued a PowerShell command like this, for an initial Proof of Concept:
get-ADUser MarySmith -properties * | Export-CSV -path C:\SOME\PATH.csv
What we found was that there is no mention there of the MaryJones folder at all. There is a HomeDirectory property, but it's empty.
Digging a little further, in Active Directory Users and Computers (ADUC) when we pull up properties for the user, we also don't see a difference for Profile Path, Login script, Home Folder ... all empty. And yet when the user (MarySmith) logs in, the NTUSER.DAT file in C:\USERS\MaryJones gets updated.
Who can help us understand how to retrieve the correct information, and maybe along the way how Windows keeps track of the fact that those names are associated? I'm convinced if we could retrieve this association we could eliminate some problems.
Thanks,
Dennis
Thanks to the suggestions of #Lee_Daily and #Thomas in the comments on the question, we've come up with a workable solution (there are a few that would not translate (caught nicely by the Try/Catch - looking into that - will update answer when understood).
UPDATE The ones that would not translate, were due to NTUSER.DAT files remaining on the system after their associated users had been removed from the directory. ***
Here are the relevant pieces of the script that we came up with:
$FOLDERS = Get-ChildItem -Path "C:\users\"
ForEach ($FOLDER in $FOLDERS) {
$NTUSER = $FOLDER.FullName + "\NTUSER.DAT"
if (Test-Path $NTUSER) { # Profile file exists
$SID = (Get-CimInstance -ClassName Win32_UserProfile | Where-Object {$_.LocalPath -like $FOLDER.FullName}).sid
$USEROBJ = New-Object System.Security.Principal.SecurityIdentifier($SID)
if ($USEROBJ -ne $NULL) {
try {
$USERNAME = $USEROBJ.Translate( [System.Security.Principal.NTAccount]).Value
}
catch [exception] {
$USERNAME = $NULL
}
}
if ($USERNAME -eq $Null) {
Write-Host "Couldn't resolve user for $SID $FOLDER "
}
else {
#Here we have a valid NTUSER path, and a profile name.
#Now we can make miracles happen.
A-Miracle-Happens($FOLDER.FullName, $USERNAME)
}
}
}
Thanks, Guys.

How do I copy a list of files and rename them in a PowerShell Loop

We are copying a long list of files from their different directories into a single location (same server). Once there, I need to rename them.
I was able to move the files until I found out that there are duplicates in the list of file names to move (and rename). It would not allow me to copy the file multiple times into the same destination.
Here is the list of file names after the move:
"10.csv",
"11.csv",
"12.csv",
"13.csv",
"14.csv",
"15.csv",
"16.csv",
"17.csv",
"18.csv",
"19.csv",
"20.csv",
"Invoices_Export(16) - Copy.csv" (this one's name should be "Zebra.csv")
I wrote a couple of foreach loops, but it is not working exactly correctly.
The script moves the files just fine. It is the rename that is not working the way I want. The first file does not rename; the other files rename. However, they leave the moved file in place too.
This script requires a csv that has 3 columns:
Path of the file, including the file name (eg. c:\temp\smefile.txt)
Destination of the file, including the file name (eg. c:\temp\smefile.txt)
New name of the file. Just the name and extention.
# Variables
$Path = (import-csv C:\temp\Test-CSV.csv).Path
$Dest = (import-csv C:\temp\Test-CSV.csv).Destination
$NN = (import-csv C:\temp\Test-CSV.csv).NewName
#Script
foreach ($D in $Dest) {
$i -eq 0
Foreach ($P in $Path) {
Copy-Item $P -destination C:\Temp\TestDestination -force
}
rename-item -path "$D" -newname $NN[$i] -force
$i += 1
}
There were no error per se, just not the outcome that I expected.
Welcome to Stack Overflow!
There are a couple ways to approach the duplicate names situation:
Check if the file exists already in the destination with Test-Path. If it does, start a while loop that appends a number to the end of the name and check if that exists. Increment the number you append after each check with Test-Path. Keep looping until Test-Path comes back $false and then break out of the loop.
Write an error message and skip that row in the CSV.
I'm going to show a refactored version of your script with approach #2 above:
$csv = Import-Csv 'C:\temp\Test-CSV.csv'
foreach ($row in $csv)
{
$fullDestinationPath = Join-Path -Path $row.Destination -ChildPath $row.NewName
if (Test-Path $fullDestinationPath)
{
Write-Error ("The path '$fullDestinationPath' already exists. " +
"Skipping row for $($row.Path).")
continue
}
# You may also want to check if $row.Path exists before attempting to copy it
Copy-Item -Path $row.Path -Destination $fullDestinationPath
}
Now that your question is answered, here are some thoughts for improving your code:
Avoid using acronyms and abbreviations in identifiers (variable names, function names, etc.) when possible. Remember that code is written for humans and someone else has to be able to understand your code; make everything as obvious as possible. Someone else will have to read your code eventually, even if it's Future-You™!
Don't Repeat Yourself (called the "DRY" principle). As Lee_daily mentioned in the comments, you don't need to import the CSV file three times. Import it once into a variable and then use the variable to access the properties.
Try to be consistent. PowerShell is case-insensitive, but you should pick a style and stick to it (i.e. ForEach or foreach, Rename-Item or rename-item, etc.). I would recommend PascalCase as PowerShell cmdlets are all in PascalCase.
Wrap literal paths in single quotes (or double quotes if you need string interpolation). Paths can have spaces in them and without quotes, PowerShell interprets a space as you are passing another argument.
$i -eq 0 is not an assignment statement, it is a boolean expression. When you run $i -eq 0, PowerShell will return $true or $false because you are asking it if the value stored in $i is 0. To assign the value 0 to $i, you need to write it like this: $i = 0.
There's nothing wrong with $i += 1, but it could be shortened to $i++, if you want to.
When you can, try to check for common issues that may come up with your code. Always think about what can go wrong. "If I copy a file, what can go wrong? Does the source file or folder exist? Is the name pulled from the CSV a valid path name or does it contain characters that are invalid in a path (like :)?" This is called defensive programming and it will save you so so many headaches. As with anything in life, be careful not to go overboard. Only check for likely scenarios; rare edge-cases should just raise errors.
Write some decent logs so you can see what happened at runtime. PowerShell provides a pair of great cmdlets called Start-Transcript and Stop-Transcript. These cmdlets log all the output that was sent to the PowerShell console window, in addition to some system information like the version of PowerShell installed on the machine. Very handy!

Search a directory structure and report folder present or missing?

I am looking for some help with writing the code in PowerShell to check for and report back.
I want to search C:\MyData\MyCustomerNames for folders MyTests, MyProducts, and MyReturns, and then report back C:\MyData\MyCustomerNames\MyTests is Present or C:\MyData\MyCustomerNames\MyProducts is Missing.
I know that the code Test-Path C:\MyData\MyCustomerNames\MyProductscould work but I also want to test for *.xml, *.docx, etc. Plus, the only part of the path that is a variable is MyCustomerNames.
If you can point me to something that would work, that would be awesome, or provide an example more so than what I provided.
Please and Thank you!
To expand on what sodawillow recommended. Save your locations in an array, then use the foreach statement to run the loop for each value in the array. You can use Get-ChildItem in an if statement to search for those directories and evaluate if they exist.
$folders = "MyTests", "MyProducts", "MyReturns"
foreach ($folder in $folders) {
if (Get-ChildItem -Path "C:\MyData\MyCustomerNames" -Filter $folder -Directory) {
"$folder exists"
} else {
"$folder does not exist"
}
}

Powershell folder creation

I have a powershell script that creates folders on our NAS for each student according to their student numbers. The names for the folders comes from a .csv file that I import from the server. This is what I have got:
Set-Location "C:\studentdata"
$StudFolders = import-csv \\servername\datafolder\studfolders.csv
ForEach ($StudFolders in $StudFolders) {
if(Test-Path -Path C:\Studentdata\$StudFolders) {
New-Item $StudFolders.Name -type directory
}else{
"Folders already created"
}
}
This script works great, if I run it only once. If I run it again, I get errors in the console window about the folders already existing. What I want to do is catch the errors with the IF part of the script, but I am not sure if I have the correct usage of the IF for powershell. This will help if I edit the .csv with more student number it will display without errors.
Can someone point me in the right direction?
EDIT:
This is what I have in the studfolders.csv
Name
2003040052
2003060213
2003060310
2003060467
Lets take a look at your logic:
you are using an if statement, which works if something returns true
you are using a test-path cmdlet which returns true if something exists
See the problem? you need to do it vice versa:
if (!(test-path ...)) { ... } # ! - is the operator to invert true to false
or you can switch if and else content, so when if executes it returns "Folders already created", and else creates folders
As a matter of coding style, I would avoid using the same variable name with different semantics, as in ($Studfolders in $Studfolders). Code like this is very hard to read a few months down the road. I generally use the singular for each object in the collection, as in ($Studfolder in $Studfolders). But if your style works for you, OK.
Previous answers have already pointed out that your logic is backwards. You need to reverse it.
Next, it doesn't look to me as though you are accessing the component of each item in the loop. When you do an Import-Csv, several things happen: The first record in the csv file is treated as a header, providing the names for the fields that follow. If there is indeed a header in your csv file, you need to reference it when you retrieve the first field from each item, even if it's the only field.
The result of an import-csv is an array of custom objects. Each custom object looks like a hashtable that contains key, value pairs. Something like this might work
Set-Location "C:\studentdata"
$StudFolders = import-csv \\servername\datafolder\studfolders.csv
ForEach ($StudFolder in $StudFolders) {
if(Test-Path -Path C:\Studentdata\$StudFolder.Name) {
"Folders already created"
}else{
New-Item $StudFolder.Name -type directory
}
}
I have presumed that the first record in the Csv file looks like this:
"Name"
That is why I referenced the field as $Studfolder.Name"
If this isn't the case, you are going to have to do something different.
Having tried everything with the script, I could not get it to catch the errors. I decided to ask my manager, and he came up with the following solution that works quite well and catches the errors.
import-csv '\\servername\datafolder\studfolders.csv'|ForEach-Object -process {
$path =$_.Name
$path='C:\Studentdata\'+$path
if (Test-Path -Path $path){
"Folder already created"
} else {
New-Item $path -type directory
}
}
Thanks to #Walter Mitty and #4c74356b41 for help try to find an answer.

Move Redirected User Documents to a new folder location at a different folder level

Our company is in the middle of a server transition. I am need some help with a little bit of an issue i ran into.
First off. Or existing domain is using Folder Redirection for their "My docs" etc. The original setup was done to the users home folder. ( ex. \server1\users\%username%*.* )
We are migrating everything over to a entirely new domain. Use accounts were created from sratch instead of migrated. We do need to move all the user documents to the associated folders. The usernames are identical but the location is differently laid out ( ex. \server2\users\%username%\My Documents*.* ) Basically we created a folder within their home folder to house their documents. This was mainly because of the whole "My documents" labeling that shows with Windows 7 as well as easy way to differentiate the folder on Mac systems.
So I started using RichCopy to push the files manually entering each users source and destination since they did not match. Does anyone have a way i could make it so that it has a certain variable to account for.
In theory:
\server1\users\%username%\
moves to
\server2\users\%username%\My Documents\
The variable would search the usernames, match them up, and push automatically for every folder within \users\
Any type of GUI interface program or even a powershell script that i can manipulate a little would be super helpful. I can't see doing this manually for each user, we have around 1000 users.
I great appreciate any help ahead of time!
So far I have been working with Powershell to run Robocopy to perform this action.
I am trying to make the powershell pull the usernames from a csv and input it into the robocopy string. Here is my code:
$usernames = import-csv c:\scripts\usernames.csv
foreach($user in $username)
{
$field1 = $user.username
Echo "$field1"
}
$source = "\\server03\Staff-MyDocs\$user"
$destination = "\\server3\users$\Staff\$user\My Documents\"
robocopy $source $destination /S /E /COPY:DATSOU /R:1 /W:5 >C:\scripts\HomeDir_robocopy.log
Any better ideas to make this work??
According to your description this should work:
$csv = 'C:\scripts\usernames.csv'
$log = 'C:\scripts\HomeDir_robocopy.log'
Import-Csv $csv | % { $_.username } | % {
$src = "\\server1\Users\$_"
$dst = "\\server2\Users\$_\My Documents\"
robocopy "$src" "$dst" /e /copyall /r:1 /w:5 /log+:"$log"
}