Replace ending on a string with regexp

Replace filetype (everything after the last dot) on a string in powershell.
"fil.fan.log" -replace "\.[^.]*$", ".txt"

Filed under: PowerShell No Comments

SAPIEN Powershell Studio, hide a form

A solution for SAPIEN PowerShell Studio to only show a form in systray and not in taskbar or in Alt+Tab.
After you create a SystemTrayMenu and SystemTrayIcon, then:

Select the form. -> ShowInTaskbar = False
And then in the code. -> $FormName.FormBorderStyle = 'FixedToolWindow'


List all members of a Local Group based on SID

This can be useful to check if a user is a member of a group. But it only lists direct members and not recursive.

function Get-LocalGroupMembers {
    $ArrMembers = @()
    $GroupSID = New-Object System.Security.Principal.SecurityIdentifier($SID)
    $GroupName = $GroupSID.Translate([System.Security.Principal.NTAccount]).Value.Split('\')[1]

    $Group = [ADSI]"WinNT://./$GroupName" 
    $Group.psbase.Invoke('Members') | ForEach-Object {
        $Member = $_.GetType().InvokeMember('AdsPath', 'GetProperty', $null, $_, $null)
        $ArrMembers += $Member.Replace('WinNT://','').Replace('/','\')
    Return $ArrMembers

List memberOf for an account

This script returns all groups that an account is a member of in Active Directory. User or computer. The argument -Recursive lists... all recursive groups, suprise.

function Get-ADGroups {
        [parameter(Mandatory = $true)][string]$Account,
    Add-Type -AssemblyName System.DirectoryServices.AccountManagement
    $ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain
    $AccountObject = [System.DirectoryServices.AccountManagement.Principal]::FindByIdentity($ct,$Account)
    If ($Recursive) {
        Return $AccountObject.GetAuthorizationGroups()
    else {
        Return $AccountObject.GetGroups()

Get-ManagedBy and Get-ManagedObjects

Who owns a computer?
Which computers do someone own?
These questions need to be answered sometimes. And the following Powershell script gets that information from AD.

function Get-ManagedBy {
        [parameter(Mandatory = $true)][string]$Computer
    Add-Type -AssemblyName System.DirectoryServices.AccountManagement
    $ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain
    $ComputerObject = [System.DirectoryServices.AccountManagement.Principal]::FindByIdentity($ct,$Computer)
    Return [System.DirectoryServices.AccountManagement.Principal]::FindByIdentity($ct,($ComputerObject.GetUnderlyingObject().managedBy))

function Get-ManagedObjects {
        [parameter(Mandatory = $true)][string]$User
    Add-Type -AssemblyName System.DirectoryServices.AccountManagement
    $ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain
    $UserObject = [System.DirectoryServices.AccountManagement.Principal]::FindByIdentity($ct,$User)
    Return $UserObject.GetUnderlyingObject().managedObjects


A simple way to test the connection to AD before running commands.

function Test-ADConnection {
    Try {
        $Connected = $true
        Add-Type -AssemblyName System.DirectoryServices.AccountManagement
        $ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain
        New-Object System.DirectoryServices.AccountManagement.PrincipalContext($ct) | Out-Null
    Catch {
        $Connected = $false
    Return $Connected

Get AD Account Properties without using ActiveDirectory cmdlets

Sometimes it's not possible or not preferred to use the Active Directory commandlets supplied by MS. Then it's lucky that the same tasks can be performed without them.

function Get-ADAccountProperties {
        [parameter(Mandatory = $true,position=0,valueFromPipeline=$true)]$Account,
	    Add-Type -AssemblyName System.DirectoryServices.AccountManagement
        $ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain
		If (-not $PSBOUNDPARAMETERS.ContainsKey('Account')) {
			$Account = $Input
        $AccountObject = [System.DirectoryServices.AccountManagement.Principal]::FindByIdentity($ct,$Account)
        If ($UnderlyingObjects) {
            Return $AccountObject.GetUnderlyingObject().Properties
        else {
            Return $AccountObject

Get-ADAccountProperties $env:USERNAME

List all drivers used in a Boot Image

How do you know which drivers are used in a boot image?
This powershell script will tell...

$Bootimage = 'C010117C'
$SCCMServer = 'Server1'
$SCCMNameSpace = 'root\sms\site_C01'

Get-WmiObject -Query "SELECT PackageID, Name, PkgSourcePath FROM SMS_BootImagePackage WHERE PackageID='$BootImage'" -ComputerName $SCCMServer -Namespace $SCCMNameSpace |
ForEach-Object {
    Write-Host "Boot Image ID: $($_.PackageID)"
    Write-Host "`tName: $($_.Name)"
    Write-Host "`tPath: $($_.PkgSourcePath)`n"
$i = 0
Get-WmiObject -Query "SELECT CI_ID FROM SMS_BootImagePackage_DriverRef WHERE PkgID='$BootImage'" -ComputerName $SCCMServer -Namespace $SCCMNameSpace | 
ForEach-Object {
    Get-WmiObject -Query "SELECT * FROM SMS_Driver WHERE CI_ID='$($_.CI_ID)'" -ComputerName $SCCMServer -Namespace $SCCMNameSpace | 
    ForEach-Object {
        Write-Host "$i Driver Name: $($_.LocalizedDisplayName)"
        Write-Host "`tVersion: $($_.DriverVersion)"
        Write-Host "`tClass: $($_.DriverClass)"
        Write-Host "`tCategory: $($_.LocalizedCategoryInstanceNames -Join '; ')"
        Write-Host "`tPath: $($_.ContentSourcePath)"


ManagedBy in Administrators by GPO/GPP

This is a neat solution, that doesn't use any script, to add the managedBy user on the computer object to the local Administrators group.
Or Remote Desktop Users or any other group you like, of course...

It's easy to limit the usage with the help of Security Filtering or OU structure.

GPO: Preferences -> Control Panel Settings -> Local Users and Groups
New -> Local Group

Local Group tab
Group name: Administrators (Built-In)
Members: %managedByUser%

Common tab
[x] Item-level targeting
-> [Targeting...]
New Item -> LDAP Query
Filter: (&(objectCategory=computer)(objectClass=computer)(cn=%ComputerName%))
Binding: LDAP:
Attribute: managedBy
Environment variable name: managedBy

New Item -> LDAP Query
Filter: (&(objectCategory=user)(objectClass=user)(distinguishedName=%managedBy%))
Binding: LDAP:
Attribute: sAMAccountName
Environment variable name: managedByUser

Edit. Happy to see in the comments that some people have found this post and have use for it 🙂


Migrate direct collection membership to AD group

Another powershell script. This one takes computers with direct membership in a collection and adds them to a AD group. Run it a second time and it removes the direct membership in the collection if the computer is a member of the AD group and if ConfigMgr knows that through AD discovery.

Import-Module ActiveDirectory
$SMSServer = "server1"
$SMSNamespace = "root\sms\site_SMS"
$SLA0 = ("C01000C8", "EntSCCM_SLA0") #AnyTime
$SLA2 = ("C0100060", "EntSCCM_SLA2") #Sunday
$SLA3 = ("C0100061", "EntSCCM_SLA3") #NoWindow
$colGroupArr = @($SLA0, $SLA2, $SLA3)

# If computer is a direct member of the collection we add it to the AD group.
# If the computer is a member of the AD group, and SCCM knows that, the direct membership is removed.
$colGroupArr | ForEach-Object {
    $Col, $Group = $_
    Write-Host Migrating computers from collectionID $col to AD group $Group
    $ADGroup = Get-ADGroup $Group
    # Get a SMS_Collection object to be able to use DeleteMembershipRule
    $delCol = get-wmiobject -query "select * from SMS_Collection where CollectionID = '$col'" -computername $SMSServer -namespace $SMSNamespace
    # Get all members of the collection
    get-wmiobject -query "select * from SMS_CM_RES_Coll_$Col" -computername $SMSServer -namespace $SMSNamespace | 
    Sort-Object -property Name |
    Where-Object {$_.IsDirect -eq $True} |
    ForEach-Object { 
        Clear-Variable ADComputer
        $ComputerName = $_.Name
        # Get the computer object from AD with Try-Catch so we do not get any errors printed out
        try {$ADComputer = Get-ADComputer $ComputerName -property memberOf}
        catch {Write-Host $ComputerName was not found in AD}
        If ($ADComputer.memberOf -eq $ADGroup.DistinguishedName) {
            # The computer is a member of the AD group. Check if ConfigMgr has discovered that
            $ADGroupSAM = $ADGroup.GroupScope.ToString() +'\\'+ $ADGroup.SamAccountName.ToString()
            $inGroup = get-wmiobject -query "select * from sms_r_system where name='$ComputerName' and systemgroupname='$ADGroupSam'" -computername $SMSServer -namespace $SMSNamespace
            If ($inGroup -ne $null) {
                # The computer is in group and ConfigMgr knows it so remove the direct membership
                Write-Host $ComputerName is a member of $ADGroup.SamAccountName so removing it from collection $delcol.Name
                $delCol.CollectionRules | 
                Where-Object {$_.RuleName -eq $ADComputer.Name -And $_.__CLASS -eq "SMS_CollectionRuleDirect"} | 
                ForEach-Object { $ReturnValue = $delCol.DeleteMembershipRule($_) }
            } Else {
                # The computer is in the group but ConfigMgr doesn't know that
                Write-Host $ComputerName is a member of $ADGroup.SamAccountName but ConfigMgr hasn"'"t discovered it yet
        } ElseIf ($ADComputer -ne $null) {
            # The computer is not a member of the AD group so add it
            Write-Host $ComputerName is a directMember in collection but not in group so adding it to $ADGroup.SamAccountName
            Add-ADGroupMember -Identity $ADGroup -Members $ADComputer