SHD – Disable User

SHD – Disable User

My last blog was about how to find the disabled user OU. Now we will go over how I disable users and move them around to the disabled OU. The next blog will combine all this together and remove inactive accounts that are within a set OU. Let’s rock this!

First first step is to get the disabled OU. In this script, you can either add it yourself or allow it to find the OU for you. It uses the Find-SHDDisabledUsersOU to find it for you.

The next step is to get the user info. We do this with the simple command, Get-ADuser.

$TargetUser = Get-ADUser -Identity $user -Properties * 

Now, I believe in removing a user from all Groups that it can be removed from. By default, the default group can’t be removed only reassigned. So, I will not go through the process of reassigning the default group. If that is part of your disabling process, you may modify this code to add it. So, lets remove all the groups.

$Targetuser.memberof | foreach-object { Remove-ADGroupMember -Identity $_.DistinguishedName -Members $targetuser.samaccountname -Confirm:$false }

We list all the memberof of the target user. Then we start a foreach-object. Inside the foreach-object we have a remove-adgroupmember. Notice the Identity tag is using the $_.DistinguishedName. This prevents errors and makes things generally faster. Only by a few milliseconds. Those milliseconds do add up over time. Then we tell it to remove the Samaccountname of the target user. The final step is what devides automation from “Damn confirmation boxes” -Confirm:$False. This flag surpresses the need to confirm everything. Thus clearing out all the groups. On average this takes about 1 second for me whie on network.

The next step is to clear all the information from the user account. 90% of the time the users that do come back, come back as something else. Most of the time, they don’t come back. We do this with a Set-ADuser command.

Set-ADUser -Identity $TargetUser.samaccountname -Department '' -Title '' -City '' -Company '' -Country '' -Description '' -Division '' -EmailAddress '' -EmployeeID '' -EmployeeNumber '' -Fax '' -Enabled $false -HomeDirectory '' -HomeDrive '' -HomePage '' -HomePhone '' -OtherName '' -Manager '' -LogonWorkstations '' -MobilePhone '' -Office '' -OfficePhone '' -Organization '' -POBox '' -PostalCode '' -ProfilePath '' -ScriptPath '' -State '' -StreetAddress '' 

The set-aduser command is straight forward. It uses the Target user samaccountname and clears anything I can. Now we will reset the password.

$Password = -join ((32..95) + (97..126) | Get-Random -Count 90 | ForEach-Object { [char]$_ })

Set-ADAccountPassword -Identity $TargetUser.Samaccountname -Reset -NewPassword (ConvertTo-SecureString -AsPlainText -String $Password -Force) 

We want the length of the password to be 90 characters long. We then start a loop and join the characters we want (Password-safe characters) and get the random of these characters. Then We loop through that to get our password. After that, we push this password into the password reset command. Set-ADAccountPassword.

Notice in the password reset command, we use the flag Reset. Then NewPassword. Notice with the newpassword tag we have a converto-securestring.

ConvertTo-SecureString -AsPlainText -String $Password -Force

We run the text as plain text and force the string. This gives us a secure password to use. As the admin, we don’t need to know the password as we can reset it later.

Now we disable the account with disable-adaccount.

Disable-ADAccount -Identity $TargetUser.samaccountname

Disable-ADAccount is very straight forward. You give it the identity of the user with the targetuser.samaccountname and your done.

The final step is to move the user to the Disabled OU. We do this with Move-ADObject.

Move-ADObject -Identity $TargetUser.samaccountname -TargetPath $DisabledOU

We are telling the system to move the AD user to the disabled ou path. Now we are done. From here you can have an email sent or any other notification information if you want to see the output. Ok, it’s time. lets put it all together.

The Script

Function Disable-SHDUser {
    <#
    .SYNOPSIS
    .DESCRIPTION
    .PARAMETER
    .EXAMPLE
    .INPUTS
    .OUTPUTS
    .NOTES
    .LINK
    #>
    [cmdletbinding()]
    param (
        [Parameter(
            ValueFromPipeline = $True,
            ValueFromPipelineByPropertyName = $True,
            HelpMessage = "Provide the target hostname",
            Mandatory = $true)][Alias('Hostname', 'cn')][String[]]$Username,
        [parameter(HelpMessage = "Moves to this OU if provided, If not, finds disable ou and moves it.")][string]$OU,
        [Parameter(HelpMessage = "Allows for custom Credential.")][System.Management.Automation.PSCredential]$Credential
    )
    
    if ($PSBoundParameters.ContainsKey('Credential')) {
        if ($PSBoundParameters.ContainsKey('OU')) {
            $DisabledOU = $OU
        } else {
            $DisabledOU = Find-SHDDisabledUsersOU -Credential $Credential
        }
        
        foreach ($user in $Username) {
            $TargetUser = Get-ADUser -Identity $user -Properties * -Credential $Credential 
            $Targetuser.memberof | foreach-object { Remove-ADGroupMember -Credential $Credential -Identity $_.DistinguishedName -Members $targetuser.samaccountname -Confirm:$false }
            Set-ADUser -Identity $TargetUser.samaccountname -Department '' -Title '' -City '' -Company '' -Country '' -Description '' -Division '' -EmailAddress '' -EmployeeID '' -EmployeeNumber '' -Fax '' -Enabled $false -HomeDirectory '' -HomeDrive '' -HomePage '' -HomePhone '' -OtherName '' -Manager '' -LogonWorkstations '' -MobilePhone '' -Office '' -OfficePhone '' -Organization '' -POBox '' -PostalCode '' -ProfilePath '' -ScriptPath '' -State '' -StreetAddress '' -Credential $Credential
            $Password = -join ((32..95) + (97..126) | Get-Random -Count 90 | ForEach-Object { [char]$_ })
            Set-ADAccountPassword -Identity $TargetUser.Samaccountname -Reset -NewPassword (ConvertTo-SecureString -AsPlainText -String $Password -Force) -Credential $Credential
            Disable-ADAccount -Identity $TargetUser.samaccountname -Credential $Credential
            Move-ADObject -Identity $TargetUser.samaccountname -TargetPath $DisabledOU -Credential $Credential
        }
    }
    else {
        if ($PSBoundParameters.ContainsKey('OU')) {
            $DisabledOU = $OU
        } else {
            $DisabledOU = Find-SHDDisabledUsersOU
        }
        foreach ($user in $Username) {
            $TargetUser = Get-ADUser -Identity $user -Properties * 
            $Targetuser.memberof | foreach-object { Remove-ADGroupMember -Identity $_.DistinguishedName -Members $targetuser.samaccountname -Confirm:$false }
            Set-ADUser -Identity $TargetUser.samaccountname -Department '' -Title '' -City '' -Company '' -Country '' -Description '' -Division '' -EmailAddress '' -EmployeeID '' -EmployeeNumber '' -Fax '' -Enabled $false -HomeDirectory '' -HomeDrive '' -HomePage '' -HomePhone '' -OtherName '' -Manager '' -LogonWorkstations '' -MobilePhone '' -Office '' -OfficePhone '' -Organization '' -POBox '' -PostalCode '' -ProfilePath '' -ScriptPath '' -State '' -StreetAddress '' -Credential $Credential
            $Password = -join ((32..95) + (97..126) | Get-Random -Count 90 | ForEach-Object { [char]$_ })
            Set-ADAccountPassword -Identity $TargetUser.Samaccountname -Reset -NewPassword (ConvertTo-SecureString -AsPlainText -String $Password -Force)
            Disable-ADAccount -Identity $TargetUser.samaccountname 
            Move-ADObject -Identity $TargetUser.samaccountname -TargetPath $DisabledOU 
        }
    }
} 
SHD – Find Disabled OU

SHD – Find Disabled OU

Have you ever started in a company and there was no documentation? The disabled OU isn’t named “Disabled Users” and things are just what the heck? This powershell script will help find that disabled user OU. Believe it or not, it’s a one liner.

((Get-ADUser -filter { enabled -eq $false }).Distinguishedname -replace '^CN=.*?,', '' | Group-Object | Sort-Object -Property Count -Descending | Select-Object -First 1).name

Lets tare this bad boy apart. First we have a Get-Aduser -filter { Enabled -eq $False}. So we want all the users in the company who are disabled. From there we are selecting only the DistinguishedName. We want to remove the first part of the DistinguishedName with a replace command. The Regex is ^CN=.*?,’,” Lets break this down.

.Distinguishedname -replace '^CN=.*?,', ''

^CN= tells us we are looking for the first “CN=” inside this string. Then we ask for the wild cards up to the first , with .*?. We tell it to replace it with nothing, aka double single quotes, .

| Group-Object

Now this gives us all the OUs that everyone who is disabled lives in. Next we group them together with Group-Object. Group-object is going to give us a clean count of each OU and how many unique items there are for each OU.

| Sort-Object -Property Count -Descending 

Next we want to organize everything with a Sort-Object. We select the count property and put it in descending order. This way we can select the first one in the final piece of the puzzle.

| Select-Object -First 1).name

Now we use the Select-object -First 1 command to get the first object from the descending list. This will give you the highest disabled users counted OU.

The Script

function Find-SHDDisabledUsersOU {
    [cmdletbinding()]
    param (
        [Parameter(HelpMessage = "Allows for custom Credential.")][System.Management.Automation.PSCredential]$Credential
    )
    if ($PSBoundParameters.ContainsKey('Credential')) {
        ((Get-ADUser -filter { enabled -eq $false } -Credential $Credential).Distinguishedname -replace '^CN=.*?,', '' | Group-Object | Sort-Object -Property Count -Descending | Select-Object -First 1).name
    }
    else {
        ((Get-ADUser -filter { enabled -eq $false }).Distinguishedname -replace '^CN=.*?,', '' | Group-Object | Sort-Object -Property Count -Descending | Select-Object -First 1).name
    }
} 

SHD – Set Those Speakers

SHD – Set Those Speakers

I hate it when someone calls and says they can’t hear their video while on a terminal server. 99% of the time is because the sound is muted on the local computer. Believe it or not, this is very simple to solve. We do this by using wscript.shell.

$Obj = New-Object -com wscript.shell

We first start by making the object wscript.shell. This little guy will give us all kinds of awesome access to a computer. Later we will wrap this up in an invoke-command.

1..100 | foreach-object { $obj.sendkeys([char]174) }

Next, we lower the volume to 0. We do this to have an absolute value. The char key 174 on the average windows computer is volume down. Thus we do it 100 times. Now we have an absolute, we can set the volume to what we want by increasing the value.

0..$Volume | foreach-object { $obj.sendkeys([char]175) }

This part will loop the volume up until the volume we tell it is reached. Using this method, we don’t have to create a sound object. We are using what is in the computer’s OS already.

The Script

function Set-SHDComputerSpeaker {
    [cmdletbinding()]
    param (
        [Parameter(
            ValueFromPipeline = $True,
            ValueFromPipelineByPropertyName = $True,
            HelpMessage = "Provide the target hostname",
            Mandatory = $true)][Alias('Hostname', 'cn')][String[]]$Computername,
        [Parameter(HelpMessage = "Allows for custom Credential.")][System.Management.Automation.PSCredential]$Credential,
        [Parameter(Helpmessage = "Increase volume by",Mandatory = $true)][int]$Volume
    )
    foreach ($computer in $Computername) {
        if (Test-Connection -ComputerName $computer -Count 1 -Quiet) {
            try {
                if ($PSBoundParameters.ContainsKey('Credential')) {
                    Invoke-Command -ComputerName $computer -Credential $Credential {
                        $Obj = New-Object -com wscript.shell
                        1..100 | foreach-object { $obj.sendkeys([char]174) }
                        0..$Volume | foreach-object { $obj.sendkeys([char]175) }
                    }
                }
                else {
                    Invoke-Command -ComputerName $computer {
                        $Obj = New-Object -com wscript.shell
                        1..100 | foreach-object { $obj.sendkeys([char]174) }
                        0..$Volume | foreach-object { $obj.sendkeys([char]175) }
                    }
                }
            }
            catch {
                Write-Warning "Unable to capture Data from $Computer."
            }
        }
        else {
            Write-Warning "$Computer is offline."
        }
    }
}

As stated above, we wrapped up the code into an invoke-command and placed some testing around it. Now all you have to do is:

Set-SHDComputerSpeaker -Computername 'Workstation1','Workstation2' -Volume 50

Or you can add the credential’s tag.

Set-SHDComputerSpeaker -Computername 'Worktation1',"Workstation2' -Volume 50 -Credential (Get-Credential)

I hope this is helpful to you. Share it with others if you find this useful.

SHD – Set Mac Structure

SHD – Set Mac Structure

I hate it when you get a mac address that’s not in the right format. Last week I got the mac address XX-XX-XX-XX when I needed to input it as XX:XX:XX:XX. So aggravating. So, here comes PowerShell to help. First, let’s validate the mac address. Second, let’s change out the pattern, and finally, we display the information.

Validate Mac Address

To validate a mac address we need to use a regex. I like the input to validate the pattern for us.

[parameter(Mandatory = $True)][ValidatePattern("^([0-9A-Fa-f]{2}[: \.-]){5}([0-9A-Fa-f]{2})$")][string]$MacAddress,

Let’s take a look at the validate pattern. ^([0-9A-Fa-f]{2}[: .-]){5}([0-9A-Fa-f]{2})$ The [0-9A-Fa-f] searches or the number 0-9, all the letters A,B,C,D,E,F, and the letters a,b,c,d,e,f. {2} states to look for only two of these characters. [: .-] is the next few characters we are searching for. This is the separator area of the mac address. xx:xx. From here we make sure all of this is repeated 5 times. Thus we need to make sure it’s grouped together using the preferences. ([0-9A-Fa-f){2}[: .-]). Now, this is grouped together, we want it to repeat 5 times. We don’t want it to repeat every time because the last subset does not have a separator. We do this using {5} after our group. Finally, we ask for the same thing again. ([0-9A-Fa-f]{2}). We finish it off with $.

Editing the Separators

Now we have our mac address validated we need to start building a way to replace the separators. First we need to setup the patter like above.

$Pattern = '[0-9A-Fa-f]'

Now this is the patter we are gong to look for. We want all the 0 – 9, A,B,C,D,E,F,a,b,c,d,e,f.

$Mac = $MacAddress -replace $Pattern, $Seperator

With this command we are taking the validated mac address, searching for the patter, and replacing the separators with the provided separator. Next, we can uppercase or lower case the mac address using $Mac.ToUpper() or $Mac.ToLower().

The Script

Below is the script that will make life easier for everyone. Notice, I gave the option to add the output to the clipboard.

function Set-SHDMacAddressStructure {
    [cmdletbinding()]
    param (
        [parameter(Mandatory = $True)][ValidatePattern("^([0-9A-Fa-f]{2}[: \.-]){5}([0-9A-Fa-f]{2})$")][string]$MacAddress,
        [parameter(Mandatory = $true)][String]$Seperator,
        [Parameter(HelpMessage = "Changes the case")][Validateset("UpperCase", "LowerCase")]$Case,
        [parameter(helpmessage = "Added mac to clipboard")][switch]$ToClipboard
    )
    $Pattern = '[^a-zA-Z0-9]'
    $Mac = $MacAddress -replace $Pattern, $Seperator
    if ($case -eq "UpperCase") {
        if ($ToClipboard) {
            $Mac.ToUpper() | clip 
            $Mac.ToUpper()
        } else {
            $Mac.ToUpper()
        }
    }
    elseif ($case -eq "LowerCase") {
        if ($ToClipboard) {
            $Mac.ToLower() | clip 
            $Mac.ToLower()
        } else {
            $Mac.ToLower()
        }
    }
    else {
        if ($ToClipboard) {
            $Mac | clip 
            $Mac
        } else {
            $Mac
        }
    }
}
TPM Chips

TPM Chips

When you need to bitlocker hundreds of machines, but can’t have the machines restart, it’s best to look for the TPM chip another way instead of the standard hardware check method. The best way to do this is using a PowerShell Cim Instance.

Get-CimInstance -ClassName win32_tpm -ComputerName $Computer -Namespace "root\cimv2\Security\MicrosoftTPM"

We grab the win32_tpm class from the computer and we want to see the Microsoft compatible TPM chips. The Output gives some good and useful information that can be used later.

IsActivated_InitialValue    : True
IsEnabled_InitialValue      : True
IsOwned_InitialValue        : True
ManufacturerId              : 1398033696
ManufacturerIdTxt           : STM
ManufacturerVersion         : 73.64.17568.6659
ManufacturerVersionFull20   : 73.64.17568.6659
ManufacturerVersionInfo     :
PhysicalPresenceVersionInfo : 1.3
SpecVersion                 : 2.0, 0, 1.38
PSComputerName              : Computer1

The Trusted Computing Group has a good list of Vendor IDs that can be located here.

From here we can see Who built the unit, the spec versions which will tell us which type of bitlocker it can handle. From there we can build logic to bit lock the machine accordingly.