Related
Need to take ownership/delete folders/files in a unc path based on samaccountname
Foreach ($line in $users){
Get-Aduser -identity $line.DistinguishedName | Select samaccountname
$username = $line.samaccountname
takeown /a /r /d y /f "\\fileserver\share\$username"
Remove-Item "\\fileserver\share\$username"}
The above attempts to take ownership of everything in \\fileserver\share and I need it to only take ownership/remove the $username folder/subfolders. Also, need to be able to do a -whatif properly to see what will happen before it does. Thank you!
I think the root of your problem is that your source CSV likely doesn't have a samaccountname column so your line $username = $line.samaccountname is setting $username to $null. To fix that save the result of your Get-ADUser call, then reference that instead.
Foreach ($line in $users){
$ADUser = Get-Aduser -identity $line.DistinguishedName | Select samaccountname
$username = $ADUser.samaccountname
takeown /a /r /d y /f "\\fileserver\share\$username"
Remove-Item "\\fileserver\share\$username"}
That's it, that's my answer, the rest is just extra stuff I feel applies to the situation and might be helpful.
I've had issues trying to get ownership of files and folder before when NTFS owners were missing or corrupted (like an account is deleted and all that's left as the owner is a SID that points at nothing). Here's the function I keep on hand in case of such troublesome cases (I'm aware the verb on the function is not an approved verb, but it makes me smile so it stays!):
Function PWN-Item{
[CmdletBinding()]
Param(
[Parameter(ValueFromPipeline=$True)]
$Path
)
Begin{
If(!$Script:PWNInit){
#P/Invoke'd C# code to enable required privileges to take ownership and make changes when NTFS permissions are lacking
$AdjustTokenPrivileges = #"
using System;
using System.Runtime.InteropServices;
public class TokenManipulator
{
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
[DllImport("kernel32.dll", ExactSpelling = true)]
internal static extern IntPtr GetCurrentProcess();
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr
phtok);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name,
ref long pluid);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}
internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public static bool AddPrivilege(string privilege)
{
try
{
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_ENABLED;
retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
catch (Exception ex)
{
throw ex;
}
}
public static bool RemovePrivilege(string privilege)
{
try
{
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_DISABLED;
retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
catch (Exception ex)
{
throw ex;
}
}
}
"#
add-type $AdjustTokenPrivileges
#Activate necessary admin privileges to make changes without NTFS perms
[void][TokenManipulator]::AddPrivilege("SeRestorePrivilege") #Necessary to set Owner Permissions
[void][TokenManipulator]::AddPrivilege("SeBackupPrivilege") #Necessary to bypass Traverse Checking
[void][TokenManipulator]::AddPrivilege("SeTakeOwnershipPrivilege") #Necessary to override FilePermissions
$Script:PWNInit = $True
}
#Obtain a copy of the initial ACL
#$FSOACL = Get-ACL $FSO - gives error when run against a folder with no admin perms or ownership
}
Process{
ForEach($Item in $Path){
$FSO = Get-Item $Item
#Create a new ACL object for the sole purpose of defining a new owner, and apply that update to the existing folder's ACL
$NewOwnerACL = If($FSO -is [System.IO.DirectoryInfo]){New-Object System.Security.AccessControl.DirectorySecurity}else{New-Object System.Security.AccessControl.FileSecurity}
#Establish the folder as owned by BUILTIN\Administrators, guaranteeing the following ACL changes can be applied
$Admin = New-Object System.Security.Principal.NTAccount("BUILTIN\Administrators")
$NewOwnerACL.SetOwner($Admin)
#Merge the proposed changes (new owner) into the file/folder's actual ACL
$FSO.SetAccessControl($NewOwnerACL)
#Add full control for administrators
$Rights = [System.Security.AccessControl.FileSystemRights]"FullControl"
$InheritanceFlag = If($FSO -is [System.IO.DirectoryInfo]){[System.Security.AccessControl.InheritanceFlags]"ObjectInherit,ContainerInherit"}else{[System.Security.AccessControl.InheritanceFlags]::None}
$PropagationFlag = [System.Security.AccessControl.PropagationFlags]::None
$objType =[System.Security.AccessControl.AccessControlType]::Allow
$objACE = New-Object System.Security.AccessControl.FileSystemAccessRule($Admin, $Rights, $InheritanceFlag, $PropagationFlag, $objType)
#Get fresh copy of ACL
$objACL = Get-Acl $FSO.FullName
#Clear any DENY rules for the local admin group
$objACL.Access|?{$_.IdentityReference -eq $admin -and $_.AccessControlType -eq [System.Security.AccessControl.AccessControlType]::Deny}|%{$objACL.RemoveAccessRule($_)}
#Add Full Control here
$objACL.AddAccessRule($objACE)
#Set updated ACL
Set-Acl $FSO.FullName $objACL
}
}
}
You can just feed it paths and it'll take care of them all. Example usage:
"\\fileserver\share\jim","\\fileserver\share\bob","\\fileserver\share\mark"|PWN-Item
or
PWN-Item "\\fileserver\share\$username"
I am trying to set permissions to a folder via Powershell Following is the code:
$acl = Get-Acl $folderPath
$acl.SetAccessRuleProtection($True, $True)
$ruleOwner = New-Object System.Security.AccessControl.FileSystemAccessRule($group,"Modify", "ContainerInherit, ObjectInherit", "None", "Allow")
$acl.AddAccessRule($ruleOwner)
Set-Acl $folderPath $acl
Once I ran this code and try to open the Security tab of the concerned folder, I am getting the error message:
The permissions on [folder name] are incorrectly ordered, which may cause some entries to be ineffective.
What is the correct way to set permission on a folder to a specific group?
Access rules (ACEs) need to be ordered in a certain way inside an ACL.
Basically, the order is
All explicit ACEs are placed in a group before any inherited ACEs.
Within the group of explicit ACEs, access-denied ACEs are placed before access-allowed ACEs.
Inherited ACEs are placed in the order in which they are inherited. ACEs inherited from the child object's parent come first, then ACEs inherited from the grandparent, and so on up the tree of objects.
For each level of inherited ACEs, access-denied ACEs are placed before access-allowed ACEs.
If this order somehow gets mixed-up, you will see the "Permissions incorrectly ordered" error message.
To rearrange the order of the permissions, you could use the below function:
function Repair-DirectoryPermissions {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[ValidateScript({Test-Path $_ -PathType Container})]
[string]$Path
)
$acl = Get-Acl -Path $Path
# create a new empty ACL object
$newAcl = New-Object System.Security.AccessControl.DirectorySecurity
# copy the access rules from the existing ACL to the new one in the correct order
# first the explicit DENY rules
$acl.Access | Where-Object { !$_.IsInherited -and $_.AccessControlType -eq 'Deny' } | ForEach-Object {
$newAcl.AddAccessRule($_)
}
# next the explicit ALLOW rules
$acl.Access | Where-Object { !$_.IsInherited -and $_.AccessControlType -eq 'Allow' } | ForEach-Object {
$newAcl.AddAccessRule($_)
}
# finally the inherited rules
$acl.Access | Where-Object { $_.IsInherited } | ForEach-Object {
$newAcl.AddAccessRule($_)
}
# set the the reordered ACL to the directory object
Set-Acl -Path $Path -AclObject $newAcl
}
And use it like:
Repair-DirectoryPermissions -Path 'D:\Blah'
While doing this, you may get an exception telling you that you need the SeSecurityPrivilege permission to perform this action.
To get that, add another function on top of the script:
function Enable-Privilege {
[CmdletBinding(ConfirmImpact = 'low', SupportsShouldProcess = $false)]
[OutputType('System.Boolean')]
Param(
[Parameter(Mandatory = $true, Position = 0)]
[ValidateSet(
"SeAssignPrimaryTokenPrivilege", "SeAuditPrivilege", "SeBackupPrivilege", "SeChangeNotifyPrivilege",
"SeCreateGlobalPrivilege", "SeCreatePagefilePrivilege", "SeCreatePermanentPrivilege",
"SeCreateSymbolicLinkPrivilege", "SeCreateTokenPrivilege", "SeDebugPrivilege", "SeEnableDelegationPrivilege",
"SeImpersonatePrivilege", "SeIncreaseBasePriorityPrivilege", "SeIncreaseQuotaPrivilege",
"SeIncreaseWorkingSetPrivilege", "SeLoadDriverPrivilege", "SeLockMemoryPrivilege",
"SeMachineAccountPrivilege", "SeManageVolumePrivilege", "SeProfileSingleProcessPrivilege",
"SeRelabelPrivilege", "SeRemoteShutdownPrivilege", "SeRestorePrivilege", "SeSecurityPrivilege",
"SeShutdownPrivilege", "SeSyncAgentPrivilege", "SeSystemEnvironmentPrivilege", "SeSystemProfilePrivilege",
"SeSystemtimePrivilege", "SeTakeOwnershipPrivilege", "SeTcbPrivilege", "SeTimeZonePrivilege",
"SeTrustedCredManAccessPrivilege", "SeUndockPrivilege", "SeUnsolicitedInputPrivilege")]
[String]$Privilege,
[Parameter(Position = 1)]
$ProcessId = $PID,
[switch]$Disable
)
begin {
Add-Type -TypeDefinition #'
using System;
using System.Runtime.InteropServices;
public class Privilege {
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid {
public int Count;
public long Luid;
public int Attr;
}
internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public static bool EnablePrivilege(long processHandle, string privilege, bool disable) {
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = new IntPtr(processHandle);
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
if(disable) { tp.Attr = SE_PRIVILEGE_DISABLED; }
else { tp.Attr = SE_PRIVILEGE_ENABLED; }
retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
}
'#
}
process {
try {
$proc = Get-Process -Id $ProcessId -ErrorAction Stop
$name = $proc.ProcessName
$handle = $proc.Handle
$action = if ($Disable) { 'Disabling' } else { 'Enabling' }
Write-Verbose ("{0} '{1}' for process {2}" -f $action, $Privilege, $name)
[Privilege]::EnablePrivilege($handle, $Privilege, [bool]$Disable)
}
catch {
throw
}
}
}
and call both functions:
Enable-Privilege -Privilege SeSecurityPrivilege
Repair-DirectoryPermissions -Path 'D:\Blah'
I am trying to create a script to remove all but the newest certificate from any given smart card (in the SC Reader at the time). This is something that I intend to be able to distribute to end users, so it should be self sufficient. My first issue is reading the certificates on the card. I do not want to affect any certificates not on the smart card, so I looked for solution that directly read from the card, and I found this gem:
How to enumerate all certificates on a smart card (PowerShell)
It's old, but it looks like it should do what I need. It really does seem to work in general but PowerShell ISE crashes when I get to the line:
$store = new-object System.Security.Cryptography.X509Certificates.X509Store($hwStore)
I can create a generic store which defaults to the 'My' store by excluding the ($hwStore) from that line without issues, but specifying that store reliably crashes my PowerShell ISE.
Here is the function from that site, the line I have issue with is near the bottom.
function Get-SCUserStore {
[string]$providerName ="Microsoft Base Smart Card Crypto Provider"
# import CrytoAPI from advapi32.dll
$signature = #"
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptGetProvParam(
IntPtr hProv,
uint dwParam,
byte[] pbProvData,
ref uint pdwProvDataLen,
uint dwFlags);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptDestroyKey(
IntPtr hKey);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptAcquireContext(
ref IntPtr hProv,
string pszContainer,
string pszProvider,
uint dwProvType,
long dwFlags);
[DllImport("advapi32.dll", CharSet=CharSet.Auto)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptGetUserKey(
IntPtr hProv,
uint dwKeySpec,
ref IntPtr phUserKey);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptGetKeyParam(
IntPtr hKey,
uint dwParam,
byte[] pbData,
ref uint pdwDataLen,
uint dwFlags);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptReleaseContext(
IntPtr hProv,
uint dwFlags);
"#
$CryptoAPI = Add-Type -member $signature -name advapiUtils -Namespace CryptoAPI -passthru
# set some constants for CryptoAPI
$AT_KEYEXCHANGE = 1
$AT_SIGNATURE = 2
$PROV_RSA_FULL = 1
$KP_CERTIFICATE = 26
$PP_ENUMCONTAINERS = 2
$PP_CONTAINER = 6
$PP_USER_CERTSTORE = 42
$CRYPT_FIRST = 1
$CRYPT_NEXT = 2
$CRYPT_VERIFYCONTEXT = 0xF0000000
[System.IntPtr]$hProvParent=0
$contextRet = $CryptoAPI::CryptAcquireContext([ref]$hprovParent,$null,$providerName,$PROV_RSA_FULL,$CRYPT_VERIFYCONTEXT)
[Uint32]$pdwProvDataLen = 0
[byte[]]$pbProvData = $null
$GetProvParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_CONTAINER,$pbProvData,[ref]$pdwProvDataLen,0)
if($pdwProvDataLen -gt 0)
{
$ProvData = new-Object byte[] $pdwProvDataLen
$GetKeyParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_CONTAINER,$ProvData,[ref]$pdwProvDataLen,0)
}
$enc = new-object System.Text.UTF8Encoding($null)
$keyContainer = $enc.GetString($ProvData)
write-host " The Default User Key Container:" $keyContainer
[Uint32]$pdwProvDataLen = 0
[byte[]]$pbProvData = $null
$GetProvParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_USER_CERTSTORE,$pbProvData,[ref]$pdwProvDataLen,0)
if($pdwProvDataLen -gt 0)
{
$ProvData = new-Object byte[] $pdwProvDataLen
$GetKeyParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_USER_CERTSTORE,$ProvData,[ref]$pdwProvDataLen,0)
[uint32]$provdataInt = [System.BitConverter]::ToUInt32($provdata,0)
[System.IntPtr]$hwStore = $provdataInt
}
$store = new-object System.Security.Cryptography.X509Certificates.X509Store($hwStore)
# release smart card
$ReleaseContextRet = $CryptoAPI::CryptReleaseContext($hprovParent,0)
return $store
}
I don't have any experience with P/Invoke (I think I said that right), so I am unsure how to troubleshoot commands derived from things imported that way.
Edit: The providers that are listed by certutil -scinfo -silent are:
Microsoft Base Smart Card Crypto Provider
Microsoft Smart Card Key Storage Provider
I have tried both of those in the below script with the same end result. The second of which gives me � characters when the script tells me what my default user key container is, so I have a feeling that it is not correct.
I did also try the x86 version of PowerShell, as suggested by Vesper. The application does not crash, and it does return a valid store with my smart card's certificate(s) on it. Now the issue is that I can't send that out to users, because expecting them to be able to navigate to the x86 version of PowerShell and then run a script with it is like expecting my dog to make me waffles... I suppose it could happen, but more likely than not something will go wrong and I'll end up having to do it myself anyway.
Edit2: Ok, so I guess I'll force that part of the script to run in x86 mode. I will post an answer with my updated code and accept it. If #Vesper posts an answer about the 64/32 bit thing (hopefully with a hair more info) I will accept his answer so that he gets credit since his comment is what lead me to the solution.
So, the main problem is actually that you're linking an x86 DLL into a x64 Powershell process. You can check whether your Powershell process is x64 like here (by querying (Get-Process -Id $PID).StartInfo.EnvironmentVariables["PROCESSOR_ARCHITECTURE"]), and if an x64 Powershell detected, start manually a Powershell (x86) located at $env:windir\syswow64\WindowsPowerShell\v1.0\powershell.exe with the same script. To get the full name of the script, use $MyInvocation.MyCommand.Definition. If Powershell is detected as x86, you proceed with importing the type and run the enumeration. An example:
$Arch = (Get-Process -Id $PID).StartInfo.EnvironmentVariables["PROCESSOR_ARCHITECTURE"];
$Arch
if ($arch -eq "AMD64") {
$here=$myinvocation.mycommand.definition
"$here launched as $arch!"
start-process C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -NoNewWindow -ArgumentList $here -wait
return
}
"now running under x86"
So my solution was to check if the powershell session is running in 32 or 64 bit mode, and if it is running in 64 bit mode (most likely) then it will run the original script as a job using the -RunAs32 argument switch. If it's already running in 32 bit mode it will simply invoke the scriptblock in the current session. Final script to get certificates off a smart card (as an x509 Certificate Store) ended up being:
$RunAs32Bit = {
[string]$providerName ="Microsoft Base Smart Card Crypto Provider"
# import CrytoAPI from advapi32.dll
$signature = #"
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptGetProvParam(
IntPtr hProv,
uint dwParam,
byte[] pbProvData,
ref uint pdwProvDataLen,
uint dwFlags);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptDestroyKey(
IntPtr hKey);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptAcquireContext(
ref IntPtr hProv,
string pszContainer,
string pszProvider,
uint dwProvType,
long dwFlags);
[DllImport("advapi32.dll", CharSet=CharSet.Auto)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptGetUserKey(
IntPtr hProv,
uint dwKeySpec,
ref IntPtr phUserKey);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptGetKeyParam(
IntPtr hKey,
uint dwParam,
byte[] pbData,
ref uint pdwDataLen,
uint dwFlags);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptReleaseContext(
IntPtr hProv,
uint dwFlags);
"#
$CryptoAPI = Add-Type -member $signature -name advapiUtils -Namespace CryptoAPI -passthru
# set some constants for CryptoAPI
$AT_KEYEXCHANGE = 1
$AT_SIGNATURE = 2
$PROV_RSA_FULL = 1
$KP_CERTIFICATE = 26
$PP_ENUMCONTAINERS = 2
$PP_CONTAINER = 6
$PP_USER_CERTSTORE = 42
$CRYPT_FIRST = 1
$CRYPT_NEXT = 2
$CRYPT_VERIFYCONTEXT = 0xF0000000
[System.IntPtr]$hProvParent=0
$contextRet = $CryptoAPI::CryptAcquireContext([ref]$hprovParent,$null,$providerName,$PROV_RSA_FULL,$CRYPT_VERIFYCONTEXT)
[Uint32]$pdwProvDataLen = 0
[byte[]]$pbProvData = $null
$GetProvParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_CONTAINER,$pbProvData,[ref]$pdwProvDataLen,0)
if($pdwProvDataLen -gt 0)
{
$ProvData = new-Object byte[] $pdwProvDataLen
$GetKeyParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_CONTAINER,$ProvData,[ref]$pdwProvDataLen,0)
}
$enc = new-object System.Text.UTF8Encoding($null)
$keyContainer = $enc.GetString($ProvData)
write-host " The Default User Key Container:" $keyContainer
[Uint32]$pdwProvDataLen = 0
[byte[]]$pbProvData = $null
$GetProvParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_USER_CERTSTORE,$pbProvData,[ref]$pdwProvDataLen,0)
if($pdwProvDataLen -gt 0)
{
$ProvData = new-Object byte[] $pdwProvDataLen
$GetKeyParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_USER_CERTSTORE,$ProvData,[ref]$pdwProvDataLen,0)
[uint32]$provdataInt = [System.BitConverter]::ToUInt32($provdata,0)
[System.IntPtr]$hwStore = $provdataInt
}
$store = new-object System.Security.Cryptography.X509Certificates.X509Store($hwStore)
# release smart card
$ReleaseContextRet = $CryptoAPI::CryptReleaseContext($hprovParent,0)
return $store
}
#Run the code in 32bit mode if PowerShell isn't already running in 32bit mode
If($env:PROCESSOR_ARCHITECTURE -ne "x86"){
Write-Warning "Non-32bit architecture detected, collecting certificate information in separate 32bit process."
$Job = Start-Job $RunAs32Bit -RunAs32
$SCStore = $Job | Wait-Job | Receive-Job
}Else{
$SCStore = $RunAs32Bit.Invoke()
}
I have been attempting to solve this same problem, and have come up with the following code. This is exactly what you have, with a couple of additions to deal with the 64-bit environment. This should do what you want without re-launching PowerShell as a 32-bit process.
function Get-SCUserStore {
[CmdletBinding()]
param(
[string]$providerName ="Microsoft Base Smart Card Crypto Provider"
)
# import CrytoAPI from advapi32.dll
$signature = #"
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptGetProvParam(
IntPtr hProv,
uint dwParam,
byte[] pbProvData,
ref uint pdwProvDataLen,
uint dwFlags);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptDestroyKey(
IntPtr hKey);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptAcquireContext(
ref IntPtr hProv,
string pszContainer,
string pszProvider,
uint dwProvType,
long dwFlags);
[DllImport("advapi32.dll", CharSet=CharSet.Auto)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptGetUserKey(
IntPtr hProv,
uint dwKeySpec,
ref IntPtr phUserKey);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptGetKeyParam(
IntPtr hKey,
uint dwParam,
byte[] pbData,
ref uint pdwDataLen,
uint dwFlags);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptReleaseContext(
IntPtr hProv,
uint dwFlags);
"#
$CryptoAPI = Add-Type -member $signature -name advapiUtils -Namespace CryptoAPI -passthru
# set some constants for CryptoAPI
$AT_KEYEXCHANGE = 1
$AT_SIGNATURE = 2
$PROV_RSA_FULL = 1
$KP_CERTIFICATE = 26
$PP_ENUMCONTAINERS = 2
$PP_CONTAINER = 6
$PP_USER_CERTSTORE = 42
$CRYPT_FIRST = 1
$CRYPT_NEXT = 2
$CRYPT_VERIFYCONTEXT = 0xF0000000
[System.IntPtr]$hProvParent=0
if([Environment]::Is64BitProcess) {
[Uint64]$pdwProvDataLen = 0
} else {
[Uint32]$pdwProvDataLen = 0
}
$contextRet = $CryptoAPI::CryptAcquireContext([ref]$hprovParent,$null,$providerName,$PROV_RSA_FULL,$CRYPT_VERIFYCONTEXT)
[byte[]]$pbProvData = $null
$GetProvParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_CONTAINER,$pbProvData,[ref]$pdwProvDataLen,0)
if($pdwProvDataLen -gt 0)
{
$ProvData = new-Object byte[] $pdwProvDataLen
$GetKeyParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_CONTAINER,$ProvData,[ref]$pdwProvDataLen,0)
}
$enc = new-object System.Text.UTF8Encoding($null)
$keyContainer = $enc.GetString($ProvData)
Write-Verbose ("The Default User Key Container:{0}" -f $keyContainer)
if([Environment]::Is64BitProcess) {
[Uint64]$pdwProvDataLen = 0
} else {
[Uint32]$pdwProvDataLen = 0
}
[byte[]]$pbProvData = $null
$GetProvParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_USER_CERTSTORE,$pbProvData,[ref]$pdwProvDataLen,0)
if($pdwProvDataLen -gt 0)
{
$ProvData = new-Object byte[] $pdwProvDataLen
$GetKeyParamRet = $CryptoAPI::CryptGetProvParam($hprovParent,$PP_USER_CERTSTORE,$ProvData,[ref]$pdwProvDataLen,0)
if([Environment]::Is64BitProcess) {
[UInt64]$provdataInt = [System.BitConverter]::ToUInt64($provdata,0)
[System.IntPtr]$hwStore = [Long]$provdataInt
} else {
[UInt32]$provdataInt = [System.BitConverter]::ToUInt32($provdata,0)
[System.IntPtr]$hwStore = $provdataInt
}
}
$store = new-object System.Security.Cryptography.X509Certificates.X509Store($hwStore)
# release smart card
$ReleaseContextRet = $CryptoAPI::CryptReleaseContext($hprovParent,0)
return $store
}
write-host ((get-WmiObject win32_PnPSignedDriver|where{$_.deviceID -like "*smartcard*"}).devicename) "reports the following certificates;"
# returns System.Security.Cryptography.X509Certificates.X509Store object representing PP_USER_CERTSTORE on Smart Card
$SCcertStore = Get-SCuserSTore
# enumerate certificates
$SCcertStore.certificates
A complete example to convert mstest coverage file into an xml file is provided below.
This example includes passing of parameters and a way to identify the current script location.
<#
.SYNOPSIS
Script to convert code coverage report into xml format that can then be published by external tools.
.DESCRIPTION
Covering code coverage staistics as part of quality improvement initiatives .
https://stackoverflow.com/questions/30215324/vstest-code-coverage-report-in-jenkins
#>
Param(
[String] $InputCoveragePath =#("..\GeneratedFiles\Docs\Reports"),
[String] $OutputCoverageFileExtension =#(".coveragexml"),
[String] $CoverageAnalysisAssembly =#("Microsoft.VisualStudio.Coverage.Analysis.dll"),
[String[]] $ExecutablePaths =#(""),
[String[]] $SymbolPaths =#("")
)
$ScriptLocation = Split-Path $script:MyInvocation.MyCommand.Path -Parent
Write-Host $ScriptLocation
<#
if(!(Test-Path "$OutputCoverageFile")){
Write-Host "Creating empty coveragle file $OutputCoverageFile"
New-Item "$OutputCoverageFile" -ItemType "file"
}
#>
$RunAs32Bit = {
Param(
[String] $InputCoveragePath =#("..\GeneratedFiles\Docs\Reports"),
[String] $OutputCoverageFileExtension =#(".coveragexml"),
[String] $CoverageAnalysisAssembly =#("Microsoft.VisualStudio.Coverage.Analysis.dll"),
[String[]] $ExecutablePaths =#(""),
[String[]] $SymbolPaths =#(""),
[String] $ScriptLocation =#(".")
)
Write-Host "[CoverageConverter][Begin]: Coverage conversion started..."
Write-Host "[CoverageConverter][InputCoveragePath]: $InputCoveragePath"
Write-Host "[CoverageConverter][OutputCoverageFileExtension]: $OutputCoverageFileExtension"
Write-Host "[CoverageConverter][CoverageAnalysisAssembly]: $CoverageAnalysisAssembly"
Write-Host "[CoverageConverter][ExecutablePaths]: $ExecutablePaths"
Write-Host "[CoverageConverter][SymbolPaths]: $SymbolPaths"
Write-Host "[CoverageConverter][ScriptLocation]: $ScriptLocation"
Import-Module -Force -Name (Join-Path "$ScriptLocation" "Utilities.psm1")
Add-Type -path "$CoverageAnalysisAssembly"
$Result = 0
if($InputCoveragePath -and (Test-Path "$InputCoveragePath") )
{
[string[]] $coverageFiles = $(Get-ChildItem -Path $InputCoveragePath -Recurse -Include *coverage)
#($coverageFiles) | ForEach-Object {
$coverageFile = $_
$coverageFileOut = (Join-Path -Path $(Split-Path $_ -Parent) -ChildPath ($(Get-Item $_).BaseName + "$OutputCoverageFileExtension"))
Write-Host "If all OK the xml will be written to: $coverageFileOut"
$info = [Microsoft.VisualStudio.Coverage.Analysis.CoverageInfo]::CreateFromFile($coverageFile, $ExecutablePaths, $SymbolPaths);
if($info){
$data = $info.BuildDataSet()
$data.WriteXml($coverageFileOut)
}
}
}
else
{
Write-Host "Please specify a valid input coverage file."
$Result = 1
}
Write-Host "[CoverageConverter][End]: Coverage conversion completed with result $Result"
return $Result
}
#Run the code in 32bit mode if PowerShell isn't already running in 32bit mode
If($env:PROCESSOR_ARCHITECTURE -ne "x86"){
Write-Warning "Non-32bit architecture detected, processing original request in separate 32bit process."
$Job = Start-Job $RunAs32Bit -RunAs32 -ArgumentList ($InputCoveragePath, $OutputCoverageFileExtension, $CoverageAnalysisAssembly, $ExecutablePaths, $SymbolPaths, $ScriptLocation)
$Result = $Job | Wait-Job | Receive-Job
}Else{
$Result = Invoke-Command -ScriptBlock $RunAs32Bit -ArgumentList ($InputCoveragePath, $OutputCoverageFileExtension, $CoverageAnalysisAssembly, $ExecutablePaths, $SymbolPaths, $ScriptLocation)
}
Searching the web, I found 2 scripts that are able to change the owner of files and folders. When testing this, it functions perfectly in PowerShell 1.0. Now I'm trying to combine both so they work recursively, because we have folders with over 500 sub directories and files in them. And it's a tremendous job to do..
We want to:
Run one script on \\server\C$\Folder (without using external tools)
to change the owner of all files and subfolders to BUILTIN\Administrators
The problem:
Each script only works for 1 file or 1 folder. How can this be combined in one script so it does all the subfoldes and files all together? Putting it in 2 different functions maybe and loop through it or..
Script1 : Change FILE owner to Admin
$File = "\\server\c$\Users\dir\Downloads\Target\TargetFile.txt"
$Account = New-Object System.Security.Principal.NTAccount("BUILTIN\Administrators")
$FileSecurity = new-object System.Security.AccessControl.FileSecurity
$FileSecurity.SetOwner($Account)
[System.IO.File]::SetAccessControl($File, $FileSecurity)
Script2 : Change FOLDER owner to Admin
$AdjustTokenPrivileges = #"
using System;
using System.Runtime.InteropServices;
public class TokenManipulator
{
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
[DllImport("kernel32.dll", ExactSpelling = true)]
internal static extern IntPtr GetCurrentProcess();
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr
phtok);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name,
ref long pluid);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}
internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public static bool AddPrivilege(string privilege)
{
try
{
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_ENABLED;
retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
catch (Exception ex)
{
throw ex;
}
}
public static bool RemovePrivilege(string privilege)
{
try
{
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_DISABLED;
retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
catch (Exception ex)
{
throw ex;
}
}
}
"#
add-type $AdjustTokenPrivileges
$Folder = Get-Item "C:\Users\dir\Downloads\Target"
[void][TokenManipulator]::AddPrivilege("SeRestorePrivilege")
[void][TokenManipulator]::AddPrivilege("SeBackupPrivilege")
[void][TokenManipulator]::AddPrivilege("SeTakeOwnershipPrivilege")
$NewOwnerACL = New-Object System.Security.AccessControl.DirectorySecurity
$Admin = New-Object System.Security.Principal.NTAccount("BUILTIN\Administrators")
$NewOwnerACL.SetOwner($Admin)
$Folder.SetAccessControl($NewOwnerACL)
You can use the SetOwner() method for folders, just like for files.
# Define the owner account/group
$Account = New-Object -TypeName System.Security.Principal.NTAccount -ArgumentList 'BUILTIN\Administrators';
# Get a list of folders and files
$ItemList = Get-ChildItem -Path c:\test -Recurse;
# Iterate over files/folders
foreach ($Item in $ItemList) {
$Acl = $null; # Reset the $Acl variable to $null
$Acl = Get-Acl -Path $Item.FullName; # Get the ACL from the item
$Acl.SetOwner($Account); # Update the in-memory ACL
Set-Acl -Path $Item.FullName -AclObject $Acl; # Set the updated ACL on the target item
}
After a week of playing around with PowerShell, I found the answer to my own question:
$Target = "\\domain.net\myFolder"
$TempFolder = 'C:\TempFolder'
$TempFile = 'C:\TempFile'
#region Load super powers
$AdjustTokenPrivileges = #"
using System;
using System.Runtime.InteropServices;
public class TokenManipulator
{
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
[DllImport("kernel32.dll", ExactSpelling = true)]
internal static extern IntPtr GetCurrentProcess();
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr
phtok);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name,
ref long pluid);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}
internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public static bool AddPrivilege(string privilege)
{
try
{
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_ENABLED;
retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
catch (Exception ex)
{
throw ex;
}
}
public static bool RemovePrivilege(string privilege)
{
try
{
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_DISABLED;
retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
catch (Exception ex)
{
throw ex;
}
}
}
"#
Add-Type $AdjustTokenPrivileges
[void][TokenManipulator]::AddPrivilege("SeRestorePrivilege")
[void][TokenManipulator]::AddPrivilege("SeBackupPrivilege")
[void][TokenManipulator]::AddPrivilege("SeTakeOwnershipPrivilege")
#endregion
$BuiltinAdmin = New-Object System.Security.Principal.NTAccount("BUILTIN\Administrators")
$BuiltinAdminFullControlAcl = New-Object System.Security.AccessControl.FileSystemAccessRule($BuiltinAdmin,"FullControl","Allow")
#region Create temp folder with Admin owner and full control
$FolderBuiltinAdminOwnerAcl = New-Object System.Security.AccessControl.DirectorySecurity
$FolderBuiltinAdminOwnerAcl.SetOwner($BuiltinAdmin)
Remove-Item $TempFolder -EA Ignore
New-Item -Type Directory -Path $TempFolder
$TempFolderAcl = Get-Acl -Path $TempFolder
$TempFolderAcl.SetAccessRule($BuiltinAdminFullControlAcl)
#endregion
#region Change folder owners to Admin
$Folders = #(Get-ChildItem -Path $Target -Directory -Recurse)
foreach ($Folder in $Folders) {
$Folder.SetAccessControl($FolderBuiltinAdminOwnerAcl)
Set-Acl -Path $Folder -AclObject $TempFolderAcl
}
#endregion
#region Create temp file with Admin owner and full control
$FileBuiltinAdminOwnerAcl = New-Object System.Security.AccessControl.FileSecurity
$FileBuiltinAdminOwnerAcl.SetOwner($BuiltinAdmin)
Remove-Item $TempFile -EA Ignore
New-Item -Type File -Path $TempFile
$TempFileAcl = Get-Acl -Path $TempFile
$TempFileAcl.SetAccessRule($BuiltinAdminFullControlAcl)
#endregion
#region Change file owners to Admin
$Files = #(Get-ChildItem -Path $Target -File -Recurse)
foreach ($File in $Files) {
$File.SetAccessControl($FileBuiltinAdminOwnerAcl)
Set-Acl -Path $File -AclObject $TempFileAcl
}
#endregion
#region Clean-up
Remove-Item $TempFile, $TempFolder
#endregion
Thank you all again for your help. Hopefully, someone else can benefit from my PowerShell research. The only think left is making it a bit more verbose, but that's for another day. It does what it needs to do, and that in the most harsh conditions where permissions are really messed up.
Issue: I wish to programmaticly (with PowerShell) take ownership of a file that I have absolutely no permissions on.
Update: I've thoroughly rewritten the question to give steps to reproduce the issue. Here's what I'm doing:
##########################################################
# Logon as UserA
##########################################################
$file = "C:\temp\file.txt"
new-item C:\temp -type dir
new-item $file -type file
# Remove inheritence
$isProtected = $true
$preserveInheritance = $true
$FileSecurity = Get-ACL $file
$FileSecurity.SetAccessRuleProtection($isProtected, $preserveInheritance)
Set-ACL $file -AclObject $FileSecurity
# Remove authenticated users
$user = "Authenticated Users"
$permission = "Modify"
$Account = New-Object System.Security.Principal.NTAccount($user)
$FileSystemRights = [System.Security.AccessControl.FileSystemRights]$permission
$InheritanceFlag = [System.Security.AccessControl.InheritanceFlags]"ContainerInherit, ObjectInherit"
$PropagationFlag = [System.Security.AccessControl.PropagationFlags]"None"
$AccessControlType =[System.Security.AccessControl.AccessControlType]::Allow
$FileSystemAccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($Account, $FileSystemRights, $InheritanceFlag, $PropagationFlag, $AccessControlType)
$FileSecurity = Get-ACL $file
$FileSecurity.RemoveAccessRuleAll($FileSystemAccessRule)
Set-ACL $file -AclObject $FileSecurity
# Remove local users
$user = "BUILTIN\Users"
$permission = "ReadAndExecute"
$Account = New-Object System.Security.Principal.NTAccount($user)
$FileSystemRights = [System.Security.AccessControl.FileSystemRights]$permission
$InheritanceFlag = [System.Security.AccessControl.InheritanceFlags]"ContainerInherit, ObjectInherit"
$PropagationFlag = [System.Security.AccessControl.PropagationFlags]"None"
$AccessControlType =[System.Security.AccessControl.AccessControlType]::Allow
$FileSystemAccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($Account, $FileSystemRights, $InheritanceFlag, $PropagationFlag, $AccessControlType)
$FileSecurity = Get-ACL $file
$FileSecurity.RemoveAccessRuleAll($FileSystemAccessRule)
Set-ACL $file -AclObject $FileSecurity
# Give the current user Full Control
$user = $env:username
$permission = "FullControl"
$FileSystemRights = [System.Security.AccessControl.FileSystemRights]$permission
$AccessControlType =[System.Security.AccessControl.AccessControlType]::Allow
$Account = New-Object System.Security.Principal.NTAccount($user)
$FileSystemAccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($Account, $FileSystemRights, $AccessControlType)
$FileSecurity = Get-ACL $file
$FileSecurity.AddAccessRule($FileSystemAccessRule)
Set-ACL $file -AclObject $FileSecurity
# Remove local administrators
$user = "BUILTIN\Administrators"
$permission = "FullControl"
$Account = New-Object System.Security.Principal.NTAccount($user)
$FileSystemRights = [System.Security.AccessControl.FileSystemRights]$permission
$InheritanceFlag = [System.Security.AccessControl.InheritanceFlags]"ContainerInherit, ObjectInherit"
$PropagationFlag = [System.Security.AccessControl.PropagationFlags]"None"
$AccessControlType =[System.Security.AccessControl.AccessControlType]::Allow
$FileSystemAccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($Account, $FileSystemRights, $InheritanceFlag, $PropagationFlag, $AccessControlType)
$FileSecurity = Get-ACL $file
$FileSecurity.RemoveAccessRuleAll($FileSystemAccessRule)
Set-ACL $file -AclObject $FileSecurity
# Set the owner to be the current user
$user = $env:username
$Account = New-Object System.Security.Principal.NTAccount($user)
$FileSecurity = new-object System.Security.AccessControl.FileSecurity
$FileSecurity.SetOwner($Account)
[System.IO.File]::SetAccessControl($file, $FileSecurity)
##########################################################
# Log off the server as UserA and logon as UserB
##########################################################
$file = "C:\temp\file.txt"
# Take ownership
$user = $env:username
$Account = New-Object System.Security.Principal.NTAccount($user)
$FileSecurity = new-object System.Security.AccessControl.FileSecurity
$FileSecurity.SetOwner($Account)
[System.IO.File]::SetAccessControl($file, $FileSecurity)
This is throwing the error:
Exception calling "SetAccessControl" with "2" argument(s): "Attempted to perform an unauthorized operation."
At line:1 char:35
+ [System.IO.File]::SetAccessControl <<<< ($path, $FileSecurity)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
Additional notes:
$error[0].innerexception is null.
The steps taken as UserA ensured that userB has absolutely no permissions on C:\temp\file.txt.
running [System.IO.File]::GetAccessControl($path) throws a similar
error (which is expected)
I am of course right-clicking PowerShell and choosing "Run as Administrator".
I've tried disabling UAC, but that does not make a difference.
I can take ownership through the GUI so there should be a way to do this programmatically with PowerShell.
What am I doing wrong?
Update and answer:
The accepted answer I posted, works, but seems to be overkill. Simply referencing the file via a UNC path seems to do the trick:
$file = "\\localhost\\c$\temp\file.txt"
# Take ownership
$user = $env:username
$Account = New-Object System.Security.Principal.NTAccount($user)
$FileSecurity = new-object System.Security.AccessControl.FileSecurity
$FileSecurity.SetOwner($Account)
[System.IO.File]::SetAccessControl($file, $FileSecurity)
I've figured this out. I can only be done with SE_RESTORE_NAME permissions.
I learned how to do that from:
http://cosmoskey.blogspot.com/2010/07/setting-owner-on-acl-in-powershell.html
And with a comment from: http://fixingitpro.com/2011/07/08/set-owner-with-powershell-%E2%80%9Cthe-security-identifier-is-not-allowed-to-be-the-owner-of-this-object%E2%80%9D/
Here's the full command that works for me:
$code = #"
using System;
using System.Runtime.InteropServices;
namespace CosmosKey.Utils
{
public class TokenManipulator
{
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
[DllImport("kernel32.dll", ExactSpelling = true)]
internal static extern IntPtr GetCurrentProcess();
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr
phtok);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name,
ref long pluid);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}
internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public const string SE_ASSIGNPRIMARYTOKEN_NAME = "SeAssignPrimaryTokenPrivilege";
public const string SE_AUDIT_NAME = "SeAuditPrivilege";
public const string SE_BACKUP_NAME = "SeBackupPrivilege";
public const string SE_CHANGE_NOTIFY_NAME = "SeChangeNotifyPrivilege";
public const string SE_CREATE_GLOBAL_NAME = "SeCreateGlobalPrivilege";
public const string SE_CREATE_PAGEFILE_NAME = "SeCreatePagefilePrivilege";
public const string SE_CREATE_PERMANENT_NAME = "SeCreatePermanentPrivilege";
public const string SE_CREATE_SYMBOLIC_LINK_NAME = "SeCreateSymbolicLinkPrivilege";
public const string SE_CREATE_TOKEN_NAME = "SeCreateTokenPrivilege";
public const string SE_DEBUG_NAME = "SeDebugPrivilege";
public const string SE_ENABLE_DELEGATION_NAME = "SeEnableDelegationPrivilege";
public const string SE_IMPERSONATE_NAME = "SeImpersonatePrivilege";
public const string SE_INC_BASE_PRIORITY_NAME = "SeIncreaseBasePriorityPrivilege";
public const string SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege";
public const string SE_INC_WORKING_SET_NAME = "SeIncreaseWorkingSetPrivilege";
public const string SE_LOAD_DRIVER_NAME = "SeLoadDriverPrivilege";
public const string SE_LOCK_MEMORY_NAME = "SeLockMemoryPrivilege";
public const string SE_MACHINE_ACCOUNT_NAME = "SeMachineAccountPrivilege";
public const string SE_MANAGE_VOLUME_NAME = "SeManageVolumePrivilege";
public const string SE_PROF_SINGLE_PROCESS_NAME = "SeProfileSingleProcessPrivilege";
public const string SE_RELABEL_NAME = "SeRelabelPrivilege";
public const string SE_REMOTE_SHUTDOWN_NAME = "SeRemoteShutdownPrivilege";
public const string SE_RESTORE_NAME = "SeRestorePrivilege";
public const string SE_SECURITY_NAME = "SeSecurityPrivilege";
public const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
public const string SE_SYNC_AGENT_NAME = "SeSyncAgentPrivilege";
public const string SE_SYSTEM_ENVIRONMENT_NAME = "SeSystemEnvironmentPrivilege";
public const string SE_SYSTEM_PROFILE_NAME = "SeSystemProfilePrivilege";
public const string SE_SYSTEMTIME_NAME = "SeSystemtimePrivilege";
public const string SE_TAKE_OWNERSHIP_NAME = "SeTakeOwnershipPrivilege";
public const string SE_TCB_NAME = "SeTcbPrivilege";
public const string SE_TIME_ZONE_NAME = "SeTimeZonePrivilege";
public const string SE_TRUSTED_CREDMAN_ACCESS_NAME = "SeTrustedCredManAccessPrivilege";
public const string SE_UNDOCK_NAME = "SeUndockPrivilege";
public const string SE_UNSOLICITED_INPUT_NAME = "SeUnsolicitedInputPrivilege";
public static bool AddPrivilege(string privilege)
{
try
{
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_ENABLED;
retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
catch (Exception ex)
{
throw ex;
}
}
public static bool RemovePrivilege(string privilege)
{
try
{
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_DISABLED;
retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
catch (Exception ex)
{
throw ex;
}
}
}
}
"#
# Take ownership
add-type $code
[void][CosmosKey.Utils.TokenManipulator]::AddPrivilege([CosmosKey.Utils.TokenManipulator]::SE_RESTORE_NAME)
$file = "\\$env:computername\c$\temp\file.txt"
$user = $env:username
$Account = New-Object System.Security.Principal.NTAccount($user)
$FileSecurity = new-object System.Security.AccessControl.FileSecurity
$FileSecurity.SetOwner($Account)
[System.IO.File]::SetAccessControl($file, $FileSecurity)
[void][CosmosKey.Utils.TokenManipulator]::RemovePrivilege([CosmosKey.Utils.TokenManipulator]::SE_RESTORE_NAME)
Try something like this:
$file = Get-Item $path
$acl= $file.GetAccessControl()
[System.Security.AccessControl.FileSecurity] $acl.SetOwner($newowner)
$file.SetAccessControl($acl)