LocalMachine.psm1
Add-Type -AssemblyName System.DirectoryServices.AccountManagement Function New-LocalUser { <# .SYNOPSIS Create a new local user. .DESCRIPTION The New-LocalUser cmdlet creates a new local user. Parameters reflect names in the GUI where possible. Two parameter sets control usage of the home folder path, a local path using "HomeFolderLocalPath" and a remote path with "HomeFolderPath" and "HomeFolderDrive". .PARAMETER SamAccountName Alias Name Specifies the user name for the new local user. .PARAMETER AccountPassword Alias Password .PARAMETER ProfilePath Specifies a path for the user profile, e.g. 'C:\Profiles\John'. .PARAMETER LogonScript Specifies a relative path against a share named NETLOGON, e.g. 'Script\Startup.bat'. A share must exist named NETLOGON, e.g. '\\ComputerName\NETLOGON\'. .PARAMETER HomeFolderLocalPath Specifies a local home folder path. .PARAMETER HomeFolderPath Specifies a remote home folder path. This must be a resolvable UNC path e.g. '\\SERVER01\Folders\John'. .PARAMETER HomeFolderDrive Specifies a drive letter to map to the home folder path. This must be a string declaring the drive e.g. 'H:'. .PARAMETER ComputerName Runs the cmdlet on the specified computer. The default is the local computer. To successfully run on a remote computer the account executing the cmdlet must have permissions on both machines. .OUTPUTS None on success. A non-terminating error if the object already exists. A terminating error if invalid data is provided, user permissions are incorrect or the SAM database cannot be accessed. .EXAMPLE New-LocalUser -SamAccountName John -AccountPassword Password01 -FullName 'John Smith' -UserMustChangePasswordOnNextLogin $true .EXAMPLE New-LocalUser -SamAccountName John -AccountPassword Password01 -HomeFolderLocalPath 'C:\Folders\John' .EXAMPLE New-LocalUser -SamAccountName John -AccountPassword Password01 -HomeFolderDrive 'H:' -HomeFolderPath '\\SERVER01\Folders\John' #> [CmdletBinding(DefaultParametersetName='LocalPath')] Param( [Parameter(Position=0,Mandatory=$true,ValueFromPipelineByPropertyName=$True,ParameterSetName='LocalPath')] [Parameter(Position=0,Mandatory=$true,ValueFromPipelineByPropertyName=$True,ParameterSetName='RemotePath')] [ValidateLength(1,20)] [Alias('Name')] [String]$SamAccountName, [Parameter(Position=1,Mandatory=$true,ValueFromPipelineByPropertyName=$True,ParameterSetName='LocalPath')] [Parameter(Position=1,Mandatory=$true,ValueFromPipelineByPropertyName=$True,ParameterSetName='RemotePath')] [ValidateLength(6,127)] [Alias('Password')] [String]$AccountPassword, [Parameter(ValueFromPipelineByPropertyName=$True,ParameterSetName='LocalPath')] [Parameter(ValueFromPipelineByPropertyName=$True,ParameterSetName='RemotePath')] [String]$FullName = '', [Parameter(ValueFromPipelineByPropertyName=$True,ParameterSetName='LocalPath')] [Parameter(ValueFromPipelineByPropertyName=$True,ParameterSetName='RemotePath')] [String]$Description = '', [Parameter(ValueFromPipelineByPropertyName=$True,ParameterSetName='LocalPath')] [Parameter(ValueFromPipelineByPropertyName=$True,ParameterSetName='RemotePath')] [String]$ProfilePath = '', [Parameter(ValueFromPipelineByPropertyName=$True,ParameterSetName='LocalPath')] [Parameter(ValueFromPipelineByPropertyName=$True,ParameterSetName='RemotePath')] [String]$LogonScript ='', [Parameter(ValueFromPipelineByPropertyName=$True,ParameterSetName='LocalPath')] [String]$HomeFolderLocalPath = '', [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$True,ParameterSetName='RemotePath')] [String]$HomeFolderPath = '', [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$True,ParameterSetName='RemotePath')] [String]$HomeFolderDrive = '', [Parameter(ValueFromPipelineByPropertyName=$True,ParameterSetName='LocalPath')] [Parameter(ValueFromPipelineByPropertyName=$True,ParameterSetName='RemotePath')] [Bool]$PasswordNeverExpires = $false, [Parameter(ValueFromPipelineByPropertyName=$True,ParameterSetName='LocalPath')] [Parameter(ValueFromPipelineByPropertyName=$True,ParameterSetName='RemotePath')] [Bool]$UserCannotChangePassword = $false, [Parameter(ValueFromPipelineByPropertyName=$True,ParameterSetName='LocalPath')] [Parameter(ValueFromPipelineByPropertyName=$True,ParameterSetName='RemotePath')] [Bool]$UserMustChangePasswordOnNextLogin = $false, [Parameter(ValueFromPipelineByPropertyName=$True,ParameterSetName='LocalPath')] [Parameter(ValueFromPipelineByPropertyName=$True,ParameterSetName='RemotePath')] [Bool]$AccountIsDisabled = $false, [Parameter(ParameterSetName='LocalPath')] [Parameter(ParameterSetName='RemotePath')] [String]$ComputerName = $env:COMPUTERNAME ) Process { try { $Context = New-Object DirectoryServices.AccountManagement.PrincipalContext('Machine',$ComputerName) $User = New-Object DirectoryServices.AccountManagement.UserPrincipal($Context) $User.SAMAccountName = $SAMAccountName $User.SetPassword($AccountPassword) $User.DisplayName = $FullName $User.Description = $Description $User.ScriptPath = $LogonScript # choose which parameter sets HomeDirectory if ($HomeFolderLocalPath.Length -gt 0) {$User.HomeDirectory = $HomeFolderLocalPath} else {$User.HomeDirectory = $HomeFolderPath} # if HomeDrive is set a share path is needed for HomeDirectory, the ParameterSet forces the correct value $User.HomeDrive = $HomeFolderDrive $User.PasswordNeverExpires = $PasswordNeverExpires $User.UserCannotChangePassword = $UserCannotChangePassword if ($UserMustChangePasswordOnNextLogin) {$User.ExpirePasswordNow()} # matching the parameter name to the GUI is the opposite of the AccountManagement object value if ($AccountIsDisabled) {$User.Enabled = $false} else {$User.Enabled = $true} # principle object needs to be initialized before calling GetUnderlyingObject() $User.Save() $User.GetUnderlyingObject().Profile = $ProfilePath $User.Save() # add all new accounts to the Users group $Group = [DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($Context, 'Users') $Group.GetUnderlyingObject().Add($User.GetUnderlyingObject().Path) $Group.Save() $Group.Dispose() # tidy up principle objects $User.Dispose() $Context.Dispose() } catch [DirectoryServices.AccountManagement.PrincipalExistsException] { # catch specific object exists exception and make it non-terminating Write-Error "Error creating the object '$SAMAccountName' on '$ComputerName. $($_.Exception.Message)" } catch [DirectoryServices.AccountManagement.PrincipalException], [Runtime.InteropServices.COMException], [UnauthorizedAccessException] { # catches all remaning exceptions that might be generated around object modification or access (from .NET and COM sources) throw "Error accessing or creating the object '$SAMAccountName' on '$ComputerName'. $($_.Exception.Message)" } } } Function Get-LocalUser { <# .SYNOPSIS Get a local user or get all local users. .DESCRIPTION The Get-LocalUser cmdlet gets a local user or gets all local users if no user is defined. The Identity parameter specifies the object using the SAMAccountName or the SID. .PARAMETER Identity Specifies a user object by using the SAMAccountName or the SID. .PARAMETER ComputerName Runs the cmdlet on the specified computer. The default is the local computer. To successfully run on a remote computer the account executing the cmdlet must have permissions on both machines. .OUTPUTS None or DirectoryServices.AccountManagement.UserPrincipal on success. A terminating error if the SAM database cannot be accessed. .EXAMPLE Get-LocalUser -Identity John #> [CmdletBinding()] Param( [String][Parameter(Position=0,ValueFromPipeline=$True)]$Identity, [String]$ComputerName = $env:COMPUTERNAME ) Begin { $Context = New-Object DirectoryServices.AccountManagement.PrincipalContext('Machine',$ComputerName) } Process { try { if ($Identity.Length -gt 0) { [DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($Context, $Identity) } else { $Searcher = New-Object DirectoryServices.AccountManagement.PrincipalSearcher(New-Object DirectoryServices.AccountManagement.UserPrincipal($Context)) $Searcher.FindAll() } } catch [DirectoryServices.AccountManagement.PrincipalException], [Runtime.InteropServices.COMException], [UnauthorizedAccessException] { throw "Error accessing the object store on '$ComputerName'. $($_.Exception.Message)" } } End { $Context.Dispose() } } Function Set-LocalUser { <# .SYNOPSIS Modify a local user. .DESCRIPTION The Set-LocalUser cmdlet modifies the properties of a local user. Parameters that are not selected will not be changed. The Identity parameter specifies the object using the SAMAccountName or the SID. .PARAMETER Identity Specifies a user object by using the SAMAccountName or the SID. .PARAMETER SamAccountName Alias Name Specifies the account name for the user. This can be used to rename a user account. .PARAMETER ProfilePath Specifies a path for the user profile, e.g. 'C:\Profiles\John'. .PARAMETER LogonScript Specifies a relative path against a share named NETLOGON, e.g. 'Script\Startup.bat'. A share must exist named NETLOGON, e.g. '\\ComputerName\NETLOGON\'. .PARAMETER HomeFolderLocalPath Specifies a local home folder path. .PARAMETER HomeFolderPath Specifies a remote home folder path. This must be a resolvable UNC path e.g. '\\SERVER01\Folders\John'. .PARAMETER HomeFolderDrive Specifies a drive letter to map to the home folder path. This must be a string declaring the drive e.g. 'H:'. .PARAMETER ComputerName Runs the cmdlet on the specified computer. The default is the local computer. To successfully run on a remote computer the account executing the cmdlet must have permissions on both machines. .OUTPUTS None on success. A non-terminating error if the object cannot be found. A terminating error if invalid data is provided, user permissions are incorrect or the SAM database cannot be accessed. .EXAMPLE Set-LocalUser -Identity John -FullName 'John Smith-Roberts' -Description '' #> [CmdletBinding(DefaultParametersetName='LocalPath')] Param( [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$True,ParameterSetName='LocalPath')] [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$True,ParameterSetName='RemotePath')] [String]$Identity, [Parameter(ParameterSetName='LocalPath')] [Parameter(ParameterSetName='RemotePath')] [ValidateLength(1,20)] [Alias('Name')] [String]$SamAccountName = '__Null', [Parameter(ParameterSetName='LocalPath')] [Parameter(ParameterSetName='RemotePath')] [String]$FullName = '__Null', [Parameter(ParameterSetName='LocalPath')] [Parameter(ParameterSetName='RemotePath')] [String]$Description = '__Null', [Parameter(ParameterSetName='LocalPath')] [Parameter(ParameterSetName='RemotePath')] [String]$ProfilePath = '__Null', [Parameter(ParameterSetName='LocalPath')] [Parameter(ParameterSetName='RemotePath')] [String]$LogonScript ='__Null', [Parameter(ParameterSetName='LocalPath')] [String]$HomeFolderLocalPath = '__Null', [Parameter(Mandatory=$true,ParameterSetName='RemotePath')] [String]$HomeFolderPath = '__Null', [Parameter(Mandatory=$true,ParameterSetName='RemotePath')] [String]$HomeFolderDrive = '__Null', [Parameter(ParameterSetName='LocalPath')] [Parameter(ParameterSetName='RemotePath')] [Nullable[Bool]]$PasswordNeverExpires = $null, [Parameter(ParameterSetName='LocalPath')] [Parameter(ParameterSetName='RemotePath')] [Nullable[Bool]]$UserCannotChangePassword = $null, [Parameter(ParameterSetName='LocalPath')] [Parameter(ParameterSetName='RemotePath')] [Nullable[Bool]]$UserMustChangePasswordOnNextLogin = $null, [Parameter(ParameterSetName='LocalPath')] [Parameter(ParameterSetName='RemotePath')] [Nullable[Bool]]$AccountIsDisabled = $null, [Parameter(ParameterSetName='LocalPath')] [Parameter(ParameterSetName='RemotePath')] [String]$ComputerName = $env:COMPUTERNAME ) Begin { $Context = New-Object DirectoryServices.AccountManagement.PrincipalContext('Machine',$ComputerName) } Process { try { $User = [DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($Context, $Identity) if ($User -ne $null) { # [String] has no [Nullable] type, so use the magic string '__Null' to indicate a parameter was not selected, this allows an empty string to be set if ($SamAccountName -ne '__Null') {$User.GetUnderlyingObject().Rename($SamAccountName)} if ($FullName -ne '__Null') {$User.DisplayName = $FullName} if ($Description -ne '__Null') {$User.Description = $Description} if ($ProfilePath -ne '__Null') {$User.GetUnderlyingObject().Profile = $ProfilePath} if ($LogonScript -ne '__Null') {$User.ScriptPath = $LogonScript} if ($HomeFolderLocalPath -ne '__Null') { $User.HomeDirectory = $HomeFolderLocalPath # HomeDrive must be empty if a local home folder path is used $User.HomeDrive = '' } if ($HomeFolderPath -ne '__Null') {$User.HomeDirectory = $HomeFolderPath} if ($HomeFolderDrive -ne '__Null') {$User.HomeDrive = $HomeFolderDrive} if ($PasswordNeverExpires -ne $null) {$User.PasswordNeverExpires = $PasswordNeverExpires} if ($UserCannotChangePassword -ne $null) {$User.UserCannotChangePassword = $UserCannotChangePassword} if ($UserMustChangePasswordOnNextLogin -ne $null) { if ($UserMustChangePasswordOnNextLogin -eq $true) {$User.ExpirePasswordNow()} else {$User.RefreshExpiredPassword()} } if ($AccountIsDisabled -ne $null) { # matching the parameter name to the GUI if ($AccountIsDisabled) {$User.Enabled = $false} else {$User.Enabled = $true} } $User.Save() $User.Dispose() } else { Write-Error "Cannot find an object with identity '$Identity' on '$ComputerName'." } } catch [DirectoryServices.AccountManagement.PrincipalException], [Runtime.InteropServices.COMException], [UnauthorizedAccessException] { throw "Error accessing or updating the object '$Identity' on '$ComputerName'. $($_.Exception.Message)" } } End { $Context.Dispose() } } Function Remove-LocalUser { <# .SYNOPSIS Remove a local user. .DESCRIPTION The Remove-LocalUser cmdlet removes a local user. The Identity parameter specifies the object using the SAMAccountName or the SID. .PARAMETER Identity Specifies a user object by using the SAMAccountName or the SID. .OUTPUTS None on success. A non-terminating error if the object cannot be found. A terminating error if user permissions are incorrect or the SAM database cannot be accessed. .EXAMPLE Remove-LocalUser -Identity John #> [CmdletBinding()] Param( [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$True)] [String]$Identity, [String]$ComputerName = $env:COMPUTERNAME ) Begin { $Context = New-Object DirectoryServices.AccountManagement.PrincipalContext('Machine',$ComputerName) } Process { $User = [DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($Context, $Identity) try { if ($User -ne $null) { $User.Delete() $User.Dispose() } else { Write-Error "Cannot find an object with identity '$Identity' on '$ComputerName'." } } catch [DirectoryServices.AccountManagement.PrincipalException], [Runtime.InteropServices.COMException], [UnauthorizedAccessException] { throw "Error accessing or updating the object '$Identity' on '$ComputerName'. $($_.Exception.Message)" } } End { $Context.Dispose() } } Function Set-LocalAccountPassword { <# .SYNOPSIS Change a user account password. .DESCRIPTION The Set-LocalAccountPassword modifies the password for a local user account. .PARAMETER Identity Specifies a user object by using the SAMAccountName or the SID. .PARAMETER ComputerName Runs the cmdlet on the specified computer. The default is the local computer. To successfully run on a remote computer the account executing the cmdlet must have permissions on both machines. .OUTPUTS None on success. A non-terminating error if the object cannot be found. A terminating error user permissions are incorrect or the SAM database cannot be accessed. .EXAMPLE Remove-LocalUser -Identity John #> [CmdletBinding()] Param( [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$True)] [Alias('Name')] [String]$Identity, [Parameter(Position=1,Mandatory=$true)][ValidateLength(6,127)] [Alias('Password')] [String]$AccountPassword, [String]$ComputerName = $env:COMPUTERNAME ) Begin { $Context = New-Object DirectoryServices.AccountManagement.PrincipalContext('Machine',$ComputerName) } Process { try { $User = [DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($Context, $Identity) if ($User -ne $null) { $User.SetPassword($AccountPassword) $User.Save() $User.Dispose() } else { Write-Error "Cannot find and object with identity '$Identity' on '$ComputerName'." } } catch [DirectoryServices.AccountManagement.PrincipalException], [Runtime.InteropServices.COMException], [UnauthorizedAccessException] { throw "Error accessing or updating the object '$Identity' on '$ComputerName'. $($_.Exception.Message)" } } End { $Context.Dispose() } } Function Test-LocalAccountPassword { <# .SYNOPSIS Test a local account password. .DESCRIPTION The Remove-LocalUser cmdlet compares a the current password to a given password. This can be useful for identifying insecure common passwords. The AccountPassword parameter specifies the given password. This is then used to try and reset the account password, success shows the password to be correct. .PARAMETER Identity Specifies a user object by using the SAMAccountName or the SID. .PARAMETER ComputerName Runs the cmdlet on the specified computer. The default is the local computer. To successfully run on a remote computer the account executing the cmdlet must have permissions on both machines. .OUTPUTS True when a password matches. False when a password does not match. A non-terminating error if the object cannot be found. A terminating error if user permissions are incorrect or the SAM database cannot be accessed. .EXAMPLE Test-LocaUserPassword -Identity John -AccountPassword Password01 #> [CmdletBinding()] Param( [Parameter(Position=0,Mandatory=$true)] [ValidateLength(1,20)] [String]$Identity, [Parameter(Position=1,Mandatory=$true)] [AllowEmptyString()] [Alias('Password')] [String]$AccountPassword, [String]$ComputerName = $env:COMPUTERNAME ) $Context = New-Object DirectoryServices.AccountManagement.PrincipalContext('Machine',$ComputerName) try { $User = [DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($Context, $Identity) if ($User -ne $null) { # if an exception is raised then the password was incorrect or violates a password policy $User.ChangePassword($AccountPassword,$AccountPassword) return $true } else { Write-Error "Cannot find an object with identity '$Identity' on '$ComputerName'." } } catch [DirectoryServices.AccountManagement.PrincipalException], [Runtime.InteropServices.COMException], [UnauthorizedAccessException] { # have to search the Message string as FullyQualifiedErrorId is always 'PasswordException' if ($_.Exception.Message.Contains('The password does not meet the password policy requirements.')) { # we got the password right, but cant change due to local or domain password policy return $true } elseif ($_.Exception.Message.Contains('The specified network password is not correct.')) { # message here would contain 'The specified network password is not correct.' return $false } # throw an exception for any other error throw "Error accessing or updating the object '$Identity' on '$ComputerName'. $($_.Exception.Message)" } } Function Add-LocalGroupMember { <# .SYNOPSIS Add one or more members to a local group. .DESCRIPTION The Add-LocalGroupMember cmdlet adds one or more members to a local group. The Identity parameter specifies the object using the SAMAccountName or the SID. .PARAMETER Identity Specifies a group object by using the SAMAccountName or the SID. .PARAMETER Members Specifies a set of user objects in a comma-separated list to add to a group. .PARAMETER ComputerName Runs the cmdlet on the specified computer. The default is the local computer. To successfully run on a remote computer the account executing the cmdlet must have permissions on both machines. .OUTPUTS None on success. A non-terminating error if the object cannot be found or the object is already a memeber of the group. A terminating error if user permissions are incorrect or the SAM database cannot be accessed. .EXAMPLE Add-LocalGroupMember -Identity Administrators -Members John,Paul,Simon .EXAMPLE 'Backup Operators','Remote Desktop Users' | Add-LocalGroupMember -Members John,Paul #> [CmdletBinding()] Param( [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$True)] [String]$Identity, [Parameter(Position=1,Mandatory=$true)] [Array]$Members, [String]$ComputerName = $env:COMPUTERNAME ) Begin { $Context = New-Object DirectoryServices.AccountManagement.PrincipalContext('Machine',$ComputerName) } Process { try { $Group = [DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($Context, $Identity) if ($Group -ne $null) { foreach ($Member in $Members) { $User = [DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($Context, $Member) if ($User -ne $null) { try { # using DirectoryServices.AccountManagement method raises: Exception "The network path was not found." if the machine is joined to a domain. #$Group.Members.Add($User) # the underlying DirectoryServices.DirectoryEntry object works fine $Group.GetUnderlyingObject().Add($User.GetUnderlyingObject().Path) } catch [Runtime.InteropServices.COMException] { if ($_.Exception.Message.Contains('The specified account name is already a member of the group.')) { # create a non-terminating error if a user is already a memeber of the group Write-Error "Cannot add object $Member to group '$Identity'. $($_.Exception.Message)" } else { throw } } } else { Write-Error "Cannot find an object with identity '$Member' on '$ComputerName'. This object was not added." } } $Group.Save() $Group.Dispose() } else { Write-Error "Cannot find an object with identity '$Identity' on '$ComputerName'." } } catch [DirectoryServices.AccountManagement.PrincipalException], [Runtime.InteropServices.COMException], [UnauthorizedAccessException] { throw "Error accessing or updating the object '$Identity' on '$ComputerName'. $($_.Exception.Message)" } } End { $Context.Dispose() } } Function Get-LocalGroupMember { <# .SYNOPSIS Get the members of a local group. .DESCRIPTION The Get-LocalGroupMember cmdlet gets all the members of a local group. The Identity parameter specifies the object using the SAMAccountName or the SID. .PARAMETER Identity Specifies a group object by using the SAMAccountName or the SID. .PARAMETER ComputerName Runs the cmdlet on the specified computer. The default is the local computer. To successfully run on a remote computer the account executing the cmdlet must have permissions on both machines. .OUTPUTS None or DirectoryServices.AccountManagement.UserPrincipal on success. A terminating error if the SAM database cannot be accessed. .EXAMPLE Get-LocalUser -Identity John #> [CmdletBinding()] Param( [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$True)] [String]$Identity = '', [String]$ComputerName = $env:COMPUTERNAME ) Begin { $Context = New-Object DirectoryServices.AccountManagement.PrincipalContext('Machine',$ComputerName) } Process { try { $Group = [DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($Context, $Identity) if ($Group -ne $null) { $Group.Members } else { Write-Error "Cannot find an object with identity '$Identity' on '$ComputerName'." } } catch [DirectoryServices.AccountManagement.PrincipalException], [Runtime.InteropServices.COMException], [UnauthorizedAccessException] { throw "Error accessing the object store on '$ComputerName'. $($_.Exception.Message)" } } End { $Context.Dispose() } } Function Remove-LocalGroupMember { <# .SYNOPSIS Remove one or more users from a local group. .DESCRIPTION The Remove-LocalGroupMember cmdlet removes one or more users from a local group. The Identity parameter specifies the object using the SAMAccountName or the SID. .PARAMETER Identity Specifies a group object by using the SAMAccountName or the SID. .PARAMETER Members Specifies a set of user objects in a comma-separated list to remove from the group. .PARAMETER ComputerName Runs the cmdlet on the specified computer. The default is the local computer. To successfully run on a remote computer the account executing the cmdlet must have permissions on both machines. .OUTPUTS None on success. A non-terminating error if the object cannot be found. A terminating error if user permissions are incorrect or the SAM database cannot be accessed. .EXAMPLE Remove-LocalGroupMember -Identity Administrators -Members John,Paul,Simon .EXAMPLE 'Backup Operators','Remote Desktop Users' | Remove-LocalGroupMember -Members John,Paul #> [CmdletBinding()] Param( [String][Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$True)]$Identity = '', [Array]$Members = @{}, [String]$ComputerName = $env:COMPUTERNAME ) Begin { $Context = New-Object DirectoryServices.AccountManagement.PrincipalContext('Machine',$ComputerName) } Process { try { $Group = [DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($Context, $Identity) if ($Group -ne $null) { foreach ($Member in $Members) { $User = [DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($Context, $Member) if ($User -ne $null) { try { # using DirectoryServices.AccountManagement object raises: Exception "The network path was not found." if the machine is joined to a domain. #$Group.Members.Remove($User) # the underlying DirectoryServices.DirectoryEntry object works fine $Group.GetUnderlyingObject().Remove($User.GetUnderlyingObject().Path) } catch [Runtime.InteropServices.COMException] { if ($_.Exception.Message.Contains('The specified account name is already a member of the group.')) { # create a non-terminating error if a user is already a memeber of the group Write-Error "Cannot remove object $Member from group '$Identity'. $($_.Exception.Message)" } else { throw } } } else { Write-Error "Cannot find an object with identity '$Member' on '$ComputerName'. This object was not removed." } } $Group.Save() $Group.Dispose() } else { Write-Error "Cannot find an object with identity '$Identity' on '$ComputerName'." } } catch [DirectoryServices.AccountManagement.PrincipalException], [Runtime.InteropServices.COMException], [UnauthorizedAccessException] { throw "Error accessing or updating the object '$Identity' on '$ComputerName'. $($_.Exception.Message)" } } End { $Context.Dispose() } } Function New-LocalGroup { <# .SYNOPSIS Create a local group. .DESCRIPTION The New-LocalGroup cmdlet creates a new local group. Parameters reflect the GUI names where possible. .PARAMETER SAMAccountName Alias Name. .PARAMETER ComputerName Runs the cmdlet on the specified computer. The default is the local computer. To successfully run on a remote computer the account executing the cmdlet must have permissions on both machines. .OUTPUTS None on success. A non-terminating error if there is an invalid SAMAccountName. A terminating error if invalid data is provided, user permissions are incorrect or the SAM database cannot be accessed. .EXAMPLE New-LocalGroup -SAMAccountName MyGroup -Description 'My group' #> [CmdletBinding()] Param( [Parameter(Position=0,Mandatory=$true,ValueFromPipelineByPropertyName=$True)] [Alias('Name')] [String]$SAMAccountName, [Parameter(Position=1,ValueFromPipelineByPropertyName=$True)] [String]$Description = '', [String]$ComputerName = $env:COMPUTERNAME ) Begin { $Context = New-Object DirectoryServices.AccountManagement.PrincipalContext('Machine',$ComputerName) } Process { try { $Group = New-Object DirectoryServices.AccountManagement.GroupPrincipal($Context) $Group.SAMAccountName = $SAMAccountName $Group.Save() # the principle object raises the following error under PowerShell 2.0 'Exception setting "Description": "Property is not valid for this store type."' $Group.GetUnderlyingObject().Description = $Description $Group.Save() $Group.Dispose() } catch [DirectoryServices.AccountManagement.PrincipalExistsException] { Write-Error "Error creating the object '$SAMAccountName' on '$ComputerName'. $($_.Exception.Message)" } catch [DirectoryServices.AccountManagement.PrincipalException], [Runtime.InteropServices.COMException], [UnauthorizedAccessException] { throw "Error accessing or creating the object '$SAMAccountName' on '$ComputerName'. $($_.Exception.Message)" } } End { $Context.Dispose() } } Function Get-LocalGroup { <# .SYNOPSIS Get a local group or all local groups. .DESCRIPTION The Get-LocalGroup cmdlet gets a defined local group or gets all local groups if no group identity is defined. The Identity parameter specifies the object using the SAMAccountName or the SID. .PARAMETER Identity Specifies a local group object by using the SAMAccountName or the SID. .PARAMETER ComputerName Runs the cmdlet on the specified computer. The default is the local computer. To successfully run on a remote computer the account executing the cmdlet must have permissions on both machines. .OUTPUTS None or DirectoryServices.AccountManagement.GroupPrincipal on success. A terminating error if the SAM database cannot be accessed. .EXAMPLE Get-LocalGroup -Identity MyGroup #> [CmdletBinding()] Param( [Parameter(Position=0,ValueFromPipeline=$True)] [String]$Identity, [String]$ComputerName = $env:COMPUTERNAME ) Begin { $Context = New-Object DirectoryServices.AccountManagement.PrincipalContext('Machine',$ComputerName) } Process { try { if ($Identity.Length -gt 0) { [DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($Context, $Identity) } else { $Searcher = New-Object DirectoryServices.AccountManagement.PrincipalSearcher(New-Object DirectoryServices.AccountManagement.GroupPrincipal($Context)) $Searcher.FindAll() } } catch [DirectoryServices.AccountManagement.PrincipalException], [Runtime.InteropServices.COMException], [UnauthorizedAccessException] { throw "Error accessing the object store on '$ComputerName'. $($_.Exception.Message)" } } End { $Context.Dispose() } } Function Set-LocalGroup { <# .SYNOPSIS Modify a local groups. .DESCRIPTION The Get-LocalGroup cmdlet modifies the properties of a local group. Parameters that are not selected will not be changed. The Identity parameter specifies the object using the SAMAccountName or the SID. .PARAMETER Identity Specifies a local user account by using the SAMAccountName or the SID. .PARAMETER SamAccountName Alias Name Specifies the account name for the group. This can be used to rename a group. .PARAMETER ComputerName Runs the cmdlet on the specified computer. The default is the local computer. To successfully run on a remote computer the account executing the cmdlet must have permissions on both machines. .OUTPUTS None on success. A non-terminating error if the object cannot be found. A terminating error if invalid data is provided, user permissions are incorrect or the SAM database cannot be accessed. .EXAMPLE Set-LocalGroup -Identity MyNewGroup -Description 'My new local group' #> [CmdletBinding()] Param( [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$True)] [String]$Identity, [Alias('Name')] [String]$SAMAccountName = '__Null', [String]$Description = '__Null', [String]$ComputerName = $env:COMPUTERNAME ) Begin { $Context = New-Object DirectoryServices.AccountManagement.PrincipalContext('Machine',$ComputerName) } Process { try { $Group = [DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($Context, $Identity) if ($Group -ne $null) { if ($SAMAccountName -ne '__Null') {$Group.GetUnderlyingObject().Rename($SAMAccountName)} if ($Description -ne '__Null') {$Group.GetUnderlyingObject().Description = $Description} $Group.Save() $Group.Dispose() } else { Write-Error "Cannot find and object with identity '$Identity' on '$ComputerName'." } } catch [DirectoryServices.AccountManagement.PrincipalException], [Runtime.InteropServices.COMException], [UnauthorizedAccessException] { throw "Error accessing or updating the object '$SAMAccountName' on '$ComputerName'. $($_.Exception.Message)" } } End { $Context.Dispose() } } Function Remove-LocalGroup { <# .SYNOPSIS Removes a local group. .DESCRIPTION The Remove-LocalGroup cmdlet removes a local group. The Identity parameter specifies the account using the SAMAccountName or the SID. .PARAMETER Identity Specifies a local group by using the SAMAccountName or the SID. .OUTPUTS None on success. A non-terminating error if the object cannot be found. A terminating error if user permissions are incorrect or the SAM database cannot be accessed. .EXAMPLE Remove-LocalGroup -Identity MyGroup #> [CmdletBinding()] Param( [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$True)] [String]$Identity, [String]$ComputerName = $env:COMPUTERNAME ) Begin { $Context = New-Object DirectoryServices.AccountManagement.PrincipalContext('Machine',$ComputerName) } Process { try { $Group = [DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($Context, $Identity) if ($Group -ne $null) { $Group.Delete() $Group.Dispose() } else { Write-Error "Cannot find an object with identity '$Identity' on '$ComputerName'." } } catch [DirectoryServices.AccountManagement.PrincipalException], [Runtime.InteropServices.COMException], [UnauthorizedAccessException] { throw "Error accessing or updating the object '$SAMAccountName' on '$ComputerName'. $($_.Exception.Message)" } } End { $Context.Dispose() } } |