temporarily take ownership of a folder - powershell

I need to temporarily take ownership of a profilefolder, in order to add permissions(ReadOnly) to members of a securitygroup. I would like to know how to achieve this in powershell.
I have before used TakeOwn.exe, but since it can't give ownership back to the original owner, I can't use it for this.
I tried using a module called PowerShellAccessControl, which I found on technet.
Import-Module $PSScriptRoot\modules\PowerShellAccessControl\PowerShellAccessControl.psd1
$path = "$PSScriptRoot\profileFolders\profile"
$AddAceParams = #{
Principal = "SecurityGroup"
FolderRights = "Read"
}
Get-SecurityDescriptor $path -PacSDOption (New-PacCommandOption -BypassAclCheck) | ForEach-Object {
$OriginalOwner = $_.Owner
$_ | Set-Owner -PassThru -Apply |
Add-AccessControlEntry #AddAceParams -PassThru |
Set-Owner -Principal $OriginalOwner -Apply
}
But this code only resultet in the following error:
New-PacCommandOption : The term 'New-PacCommandOption' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
I dont know if i should continue with this module or if there is a better way.

I tend to use the NTFSSecurity module when dealing with filesystem permissions, it's well written and I've had good success with it so far.
$path = "C:\folder"
$OriginalPermissions = Get-NTFSOwner $path
Set-NTFSOwner -Path $path -Account $env:USERNAME
Add-NTFSAccess -Path $path -Account 'DOMAIN\SecurityGroup' -AccessRights Read
Set-NTFSOwner -Path $path -Account $OriginalPermissions.Owner
Note: You do need to install the module, if you're using a modern version of Powershell this is easy as you can just use Install-Module -Name NTFSSecurity. If it's an older version you will need download and install the module manually.
EDIT:
The other option is to use Enable-Privileges to grant your account the privileges for Backup, Restore, and Security.
With these you will be able to edit the permissions without your own account having explicit permissions to the data. Use of these command is covered in the documentation in the link above. Be sure to Disable-Privileges after enabling them as it's not good practice to run with these all the time.

Related

How do I reference the current logged in user when a script is running?

So, I'm using Desktop Central to run some scripts on a bunch of machines. The script is supposed to open a zip file in the c:\users%USERNAME%\ folder, and decompress it to a folder of my choosing. The idea is to use a single script for many machines, that can leverage the c:\users\LOGGEDONUSER\downloads folder (Default TEAMS download dir). The idea is that each user will download the archive from teams, and a script will decompress and install from each users DOWNLOADS folder.
The issue is that I don't seem to know how to write a script uses a variable representing the username of the logged in user for the -path in my argument.
For instance;
Extract file
Expand-archive -path $home\Downloads\SWANDPDM_SP5.1.zip -DestinationPath C:\temp\swpdminstaller\extracted\ -Force
#Define registry values to modify to allow for no UAC
$RegistryPath = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
$Name = 'ConsentPromptBehaviorAdmin'
$Value = '0'
#Run reg change
New-ItemProperty -Path $RegistryPath -Name $Name -Value $Value -PropertyType DWORD -Force
#Run installer
Invoke-Item C:\temp\swpdminstaller\extracted\SOLIDWORKS_AND_PDM_2021_SP5.1\startswinstall.exe
#Define reg values to change back to default
$RegistryPath = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
$Name = 'ConsentPromptBehaviorAdmin'
$Value = '5'
#Run reg change
New-ItemProperty -Path $RegistryPath -Name $Name -Value $Value -PropertyType DWORD -Force
This works great if I copy the script to the machine manually, and launch the script as a user. It looks at $home and figures out the correct directory based on whomever is logged in.
However, when it runs as Desktop Central, $home doesn't mean the same location. It comes back with this;
Expand-archive : The path 'C:\Windows\system32\config\systemprofile\Downloads\SWANDPDM_SP5.1.zip' either does not
exist or is not a valid file system path.
At C:\Program Files (x86)\DesktopCentral_Agent\Computer\startup\76507\SWandPDMdecomInstall.ps1:2 char:1
+ Expand-archive -path $home\Downloads\SWANDPDM_SP5.1.zip -DestinationP ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (C:\Windows\syst...NDPDM_SP5.1.zip:String) [Expand-Archive], InvalidOpe
rationException
+ FullyQualifiedErrorId : ArchiveCmdletPathNotFound,Expand-Archive
I tried using various env variables with no luck. It seems like because it's a "Desktop central" account that's running the script remotely, I can't get it to point to the correct folder in c:\users\NAMEOFLOGGEDINUSER\
So, it thinks $home = 'C:\Windows\system32\config\systemprofile\ instead of c:\users\NAMEOFLOGGEDINUSER\
Is there a way that I can get the username of the current logged on user, assign it to a variable, and then use that variable instead of $home? Keep in mind, it needs to find the logged in user while running the script as the Desktop Central service account. I've tried running the script as various domain admins\system accounts with no luck.
I thought about doing a whoami, writing to a text file, then omitting the domain portion of the output and assigning it to a variable, but there's got to be a better way.
Any help is greatly appreciated!
EDIT: Thought I was on to something, but it didn't work. I tried;
Expand-archive -path $env:HOMEPATH\Downloads\SWANDPDM_SP5.1.zip -DestinationPath C:\temp\swpdminstaller\extracted\ -Force
I see from the comments that you found a workaround. But to answer your original question, you can't get the logged in username from the usual Powershell techniques ($env:USERNAME, whoami, etc.) when you're running the script under a different security context.
But you can check who owns the Explorer.exe process:
$User = (Get-CimInstance Win32_Process -Filter "name = 'explorer.exe'" |
Invoke-CimMethod -MethodName GetOwner).User
The "Desktop central" user will probably not have Explorer running. However, if there are multiple users logged in via RDP sessions this will return an array.

Error when changing ownership and transferring access rights

I ran into a problem, wrote a script that compresses pdf files through a program and transfers rights to a new file by copying from the old one to differentiate access to new files.
Here is the part of the code that I have is the problem
$owner = $origFile.GetAccessControl().GetOwner([System.Security.Principal.SecurityIdentifier])
$newFile = Get-Item -Path $PathoutFile
$FileSecurity = new-object System.Security.AccessControl.FileSecurity
$FileSecurity.SetOwner($owner)
[System.IO.File]::SetAccessControl($newFile, $FileSecurity)
Get-Acl -Path $origFile | Set-Acl -Path $newFile
My problem is this:
I execute the script using domain administrator privileges, everything works fine. If I use a domain user account and grant maximum rights to the directory, a compressed file is saved in it, and in this case I get the error “Attempt to perform an unauthorized operation.
I do not want to run the script under the administrator account for a simple reason, I believe that such rights are redundant for this operation. My judgments may not be correct, please help in solving this problem.
P.s actions are performed on a network directory.
Thanks in advance.
I myself found a solution to my main problem using the NTFSSecurity PowerShell module.
The transfer of access rights was performed using the Get-NTFSAccess $filein | Add-NTFSAccess $fileout

Grant permissions to a folder

How (which command) can I use to grant permissions (full_control) to a user (service_account) on a folder using PowerShell?
Thank you!
I was trying to use icacls in my PowerShell but it's not working.
There are several ways to do this. If you don't want to install a module as James suggests above then:
# Get current access permissions from folder and store in object
$Access = Get-Acl -Path $FolderPath
# Create new object with required new permissions
$NewRule = New-Object System.Security.AccessControl.FileSystemAccessRule("MyDomain\MyUserOrGroup","FullControl","ContainerInherit,ObjectInherit","None","Allow")
# Add new rule to our copy of the current rules
$Access.AddAccessRule($NewRule)
# Apply our new rule object to destination folder
Set-Acl -Path $FolderPath -AclObject $Access -ErrorAction Stop
As James mentions though, using ACLs in Powershell without a module, whilst powerful, is also a pain. I only do it when I'm sharing scripts (so that there isn't a dependency on the module).
I would recommend using the NTFSSecurity Powershell module for setting the permissions as it's much easier to use (and understand) than acls!
To add permissions for a user is just one command.
I've shown two examples for both network paths/domain account and local folder/local user. They can be mixed in any way you can set via the GUI.
Add-NTFSAccess -Path "\\sdk\data\SHAREDIR\$NAME" -Account "Domain\K_NV_TEST_R" -AccessRights FullControl
Add-NTFSAccess -Path "C:\folder\subfolder" -Account "LocalComputerName\LocalUserName" -AccessRights FullControl

On which system is get-acl resolved?

I've inherited a Powershell script that a remote customer uses to recursively search for directories and exports (to csv) multiple ACL values including Path, Owner, FileSystemRights, IdentifyReference, and AccessControlType. The script works great, but I am curious as to how the flow actually takes place. Below is partial script to show code relevant to my question below.
//Partial script begin:
get-childitem $rootdir -recurse | where-object {$_.psIscontainer -eq $true} | foreach-object {
$a = ($_.Fullname)
$b = (get-acl $_.Fullname).Owner
$c = (get-acl $_.Fullname).Access
foreach ($c1 in $c) {
$d = $c1.FileSystemRights
$e = $c1.AccessControlType
//Partial script end.
To my question: If running this script on a remote system, using admin privileges and variable $rootdir = \\someshare, on which system does the get-acl get resolved...on the system hosting the folder structure, or the remote system running the PS script and mapped to the share folder?
Thanks.
// My original question may have been a bit nebulous, so hopefully I can clarify a bit. By using get-acl on a remote system and mapped to a server share folder, will invoking get-acl cause any resource hit on the server during the ACL resolution process...disk I/O, memory, CPU. I am not a programmer, so please bear with me as I try to formulate my question properly.
Assuming that you have all authentication correctly setup (you would run into a double-hop auth problem if i understand your plan correctly) the call to Get-Acl would be executed on the system the script is run on.
From the technet article on the Get-ACL cmdlet
The Get-Acl cmdlet enables you to retrieve the security descriptor
(access control list) for a file, a folder, or even a registry key
It retrieves NTFS persmission for any folder specified, including remote folders.
In your case, it would run from the machine the script is running from, and authenticate to the remote machine using the credentials supplied to retrieve the ACL

How to export shared folder with permissions and groups associated

I'm working on a windows server 2008 r2 and I'm trying to export the configuration of shared folder with all the groups associated to them,permissions and file system permissions.
is there a way to do that?
maybe with powershell?
#edit: another problem is that I need to do that after a reboot, so I have to save the configuration in a file for example and then reimport it.
If you want to backup/restore all existing shares you could export/import the registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\Shares.
Backup:
reg export HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Shares shares.reg
Restore:
reg import shares.reg
net stop server && net start server
File/folder ACLs can be saved and restored like this:
Backup:
Get-WmiObject -Class Win32_Share -Filter 'Type = 0' | select -Expand Path | % {
$path = $_
Get-Acl $path | select #{n='Path';e={$path}}, Sddl
} | Export-Csv 'C:\path\to\acls.csv'
Restore:
Import-Csv 'C:\path\to\acls.csv' | % {
$acl = Get-Acl $_.Path
$acl.SetSecurityDescriptorSddlForm($_.Sddl)
Set-Acl -Path $_.Path -AclObject $acl
}
Interesting question, I think the only way to do so is manually getting the acl on original folder and then re-apply them to the copied folder. The cmdlet to be used are Get-Acl -path $youfolder, Copy-Item and Set-Acl
I'm working on a module (see here) that should be able to do this for you. It's a script module, so you can actually open it up and look at/modify the code. If you use it, you could do something like this (the Export-Csv call is commented out, but you can put it in after confirming this is the output you're looking for):
Get-WmiObject Win32_Share -ComputerName ServerName |
Get-AccessControlEntry #| Export-Csv -Path CsvLocation.csv
You'll get errors for built-in system shares, e.g., C$, so you may want to add an -ErrorAction SilentlyContinue and/or an -ErrorVariable to the Get-AccessControlEntry call.
To bring the permissions back in, you'd just feed the Get-AccessControl output into Add-AccessControlEntry:
Import-Csv -Path CsvLocation.csv | Add-AccessControlEntry -WhatIf
Add-AccessControlEntry prompts for confirmation by default. Use the -Force switch to suppress the prompts.
Changing this to work for the NTFS permissions is very easy, too. Just change the Get-WmiObject call into a Get-ChildItem call, and everything else should be the same.