Categories

14154

Set registry key owner

In chapter 7 of PowerShell and WMI I stated that I would post a .NET version of a script to set ownership of a registry key. The WMI method needs Vista or above so we need the .NET version for pre-Vista operating systems.

function set-regkeyowner {            
[CmdletBinding()]            
param (            
 [parameter(Mandatory=$true)]            
 [string]            
 [Validateset(“HKCR”, “HKCU”, “HKLM”, "HKUS", "HKCC")]            
  $hive,            
            
 [parameter(Mandatory=$true)]            
 [string]$key            
)              
PROCESS {             
Write-Verbose "Set Hive"            
switch ($hive){            
 “HKCR” {$reg = [Microsoft.Win32.Registry]::ClassesRoot}            
 “HKCU” {$reg = [Microsoft.Win32.Registry]::CurrentUser}            
 “HKLM” {$reg = [Microsoft.Win32.Registry]::LocalMachine}            
 "HKUS" {$reg = [Microsoft.Win32.Registry]::Users}            
 "HKCC" {$reg = [Microsoft.Win32.Registry]::CurrentConfig}            
}            
            
$permchk = [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree            
$regrights = [System.Security.AccessControl.RegistryRights]::ChangePermissions            
            
Write-Verbose "Open Key and get access control"            
$regkey = $reg.OpenSubKey($key, $permchk, $regrights)            
$rs = $regkey.GetAccessControl()            
            
Write-Verbose "Create security principal"            
$user = New-Object -TypeName Security.Principal.NTaccount -ArgumentList "Administrators"            
            
$rs.SetGroup($user)             
$rs.SetOwner($user)             
$regkey.SetAccessControl($rs)            
}            
}


Take a hive and key as parameters. Use a switch to set the Registry enumeration and then set the permissions and rights we want. Open the key and get the access controls.



Create a security principal for the Administrators group and set the group and owner in the access control. Use SetAccessControl to change the permissions

Create a process on a remote machine

We cam use the [wmiclass] to create a process but it doesn’t allow us to set the credentials. We can get round that by using a bit of .NET code. [wmiclass] is as accelerator for System.Management.ManagementClass so we go back to basics

function new-process {            
param (            
 [string]$computer="localhost",            
 [string]$procpath="C:\Program Files\Internet Explorer\iexplore.exe"            
)            
            
$conopt = New-Object System.Management.ConnectionOptions             
            
switch ($computer ) {            
 "."         {break}            
 "localhost" {break}            
 "$env:COMPUTERNAME" {break}            
 default {            
           $cred = Get-Credential            
           $conopt.UserName = $cred.UserName            
           $conopt.SecurePassword = $cred.Password            
         }            
}            
$conopt.EnablePrivileges = $true            
            
$scope = New-Object System.Management.ManagementScope             
$scope.Path = "\\$computer\root\cimv2"             
$scope.Options = $conopt             
            
$path = New-Object System.Management.ManagementPath            
$path.ClassName = "Win32_Process"              
            
$proc = New-Object System.Management.ManagementClass($scope, $path, $null)             
            
$proc.Create($procpath)             
}


 



The computer name and path to the exe we want to run are given as parameters. We create the System.Management.ConnectionOptions. If we are  targeting a remote machine we can add the credentials (doesn’t work for local machine). The switch simplifies the coding of avoid local machine



 



The scope and management path (name space and class) are set and then we create a new instance of the class. We can then use the Create method to create the process.

Deleting Local User accounts

Do you need to be able to delete local user accounts?  try this

 

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029

function remove-user {
[CmdletBinding(SupportsShouldProcess=$true)]
param (
 [parameter(ValueFromPipeline=$true,
   ValueFromPipelineByPropertyName=$true)]
 [string]$computer,
 
 [parameter(ValueFromPipeline=$true,
   ValueFromPipelineByPropertyName=$true)]
 [string]$id 
)
BEGIN {Add-Type -AssemblyName System.DirectoryServices.AccountManagement} 
PROCESS {  
 switch ($computer){
  "."    {$computer = $env:computername}
  "localhost" {$computer = $env:computername}
 }
 
 $ctype = [System.DirectoryServices.AccountManagement.ContextType]::Machine
 $context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList $ctype, $computer

 $user = [System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($context, $id)

## delete the user
if ($psCmdlet.ShouldProcess("$id", "Will be deleted")) {
    $user.Delete()
  }
} 
}

 

We use the System.DirectoryServices.AccountManagement classes to find the user we want and then call the Delete method.  It works nicely on remote machines assuming you have the required permissions.

Rounding numbers

We often need to round numbers when we are writing administration scripts – for example

PS> Get-ChildItem c:\hiberfil.sys -Force | Format-Table Name, Length -AutoSize

Name             Length
----             ------
hiberfil.sys 2213351424

 

We need the force because hiberfil.sys is a hidden file.  Looking at the file size its about 2GB but its difficult to relate to a number that size so we can try this

PS> Get-ChildItem c:\hiberfil.sys -Force | Format-Table Name, @{Name="Size";Expression={$_.Length/1GB}} -AutoSize

Name                     Size
----                     ----
hiberfil.sys 2.06134414672852

 

However there are too may numbers after the decimal point – we don’t need that level of accuracy.  The easiest way to round the numbers is to use the Math .NET class.

PS> Get-ChildItem c:\hiberfil.sys -Force | Format-Table Name,

@{Name="Size";Expression={[math]::round($_.Length/1GB,2)}}  -AutoSize

Name         Size
----         ----
hiberfil.sys 2.06

 

Which gives us a nice easy to understand display