Creating Registry DWORD entry with PowerShell

22. April 2015

ps

PowerShell Version: >2
Modules: none

 

New-ItemProperty "hklm:\SOFTWARE\Microsoft\..." -Name "testkey" -Value 1 -PropertyType "DWord"

 -Name is the RegKey Name

-Value is the Value in hexadecimal

-PropertyType defines that we want a DWORD

Project: Apply Windows hotfixes to certain users in AD group by using PowerShell

20. April 2015

ps

PowerShell Version: >2
Modules: none

Today I am documenting a little script I worked on that needed some workarounds and tweaks to function. Basically, we have a GPO that acts on shutdown (to save users a restart after hotfix installation) and should be applied for the whole domain. Some users in this domain use RDP and need these specific hotfixes so I had to find a way to apply a machine based GPO with a script to a group of users. Also, the RDC 8.1 hotfixes need to be applied in a specific order (KB2574819, KB2830477, KB2857650, KB2913751, KB3036965, KB2862019), which is why I can not work with foreach here.

#receive username from logon script
$user = Get-Content 'C:\tmp\$variables.txt' | select -index 0

$os = (Get-WMIObject Win32_OperatingSystem).name
$wusa = "C:\windows\system32\wusa.exe"
$userGroups = ([Security.Principal.WindowsIdentity]"$($user)").Groups.Translate([System.Security.Principal.NTAccount])
$LogPath = "c:\tmp\hotfixes.log"
$date = Get-Date -Format "dd.MM.yyyy hh:mm"

Start-Transcript -Path $LogPath
# Windows 7 Client hotfixes
if ($os -like "*Windows 7*")
{
    # Remotedesktop hotfixes
    if ($userGroups -like "*main_rdp_group")
    {
    "##########################################################"
    "#                   $date"
    "##########################################################"
    "User: $user"
    "Hostname: $env:COMPUTERNAME"
    "##########################################################"
    # https://support.microsoft.com/en-us/kb/2830477
    # Remote Desktop Connection (RDC) 8.1
    "Installing Windows6.1-KB2574819-v2-x64.msu..."
    & $wusa \\path_to_ad_share\Windows6.1-KB2574819-v2-x64.msu /quiet /norestart
    "Installing Windows6.1-KB2830477-x64.msu..."
    & $wusa \\path_to_ad_share\Windows6.1-KB2830477-x64.msu /quiet /norestart
    "Installing Windows6.1-KB2857650-x64.msu..."
    & $wusa \\hpath_to_ad_share\Windows6.1-KB2857650-x64.msu /quiet /norestart
    "Installing Windows6.1-KB2913751-x64.msu..."
    & $wusa \\path_to_ad_share\Windows6.1-KB2913751-x64.msu /quiet /norestart
    
    # https://support.microsoft.com/en-us/kb/3036965
    # Printing preferences window appears behind a RemoteApp window in Windows
    "Installing Windows6.1-KB3036965-x6.msu..."
    & $wusa \\path_to_ad_share\Windows6.1-KB3036965-x64.msu /quiet /norestart

    # https://support.microsoft.com/en-us/kb/2862019
    # A RemoteApp application main window takes the focus after the applications windows are maximized in Windows
    "Installing Windows6.1-KB2862019-x64.msu..."
    & $wusa \\path_to_ad_share\Windows6.1-KB2862019-x64.msu /quiet /norestart
    }
}
Stop-Transcript

As the computer based GPO would use the computername$ as the username when running, I had to find a way to get the actual username for my group-filter:

$user = Get-Content 'C:\tmp\$variables.txt' | select -index 0

I simply added some lines at the end of the existing logon script:

# check if c:\tmp exists...
$path_to_c_tmp = Test-Path c:\tmp
if ($path_to_c_tmp -eq $true)
    {
    # Gather variables for further scripts
    $env:USERNAME | Out-File 'C:\tmp\$variables.txt'
    $env:COMPUTERNAME | Out-File 'C:\tmp\$variables.txt'-Append
    $PSVersionTable.PSVersion.Major | Out-File 'C:\tmp\$variables.txt'-Append
    }
    else
    {
    # if c:\tmp does not exist create it and continue with gathering variables for further scripts
    "c:\tmp does not exist, creating...."
    New-Item c:\tmp -type directory
    # check if creation was successfull
    if ($? -eq $true)
        {
        "Success!"
        # Gather variables for further scripts
        $env:USERNAME | Out-File 'C:\tmp\$variables.txt'
        $env:COMPUTERNAME | Out-File 'C:\tmp\$variables.txt'-Append
        $PSVersionTable.PSVersion.Major | Out-File 'C:\tmp\$variables.txt'-Append
        }
        else
        {
        "Something went wrong..."
        }
    }

In this example we would only use the $env:USERNAME but I added computername and psversion also for further projects. I can now call every line of the C:\tmp\$variables.txt file with  | select -index number_of_line and use this to make the if ($userGroups -like “*main_rdp_group”) work. (If c:\tmp does not exist it will create it and gather the information again.)

I will continue working on this script to enable results in the logs and more filter options for other hotfixes. The goal here is to have one script to apply all hotfixes in the environment to the assigned target group.

Get AD Groups for local User in all PowerShell versions

17. April 2015

I pretty often filter through AD user groups and this way even works with PowerShell 1.0:

([Security.Principal.WindowsIdentity]"$($env:USERNAME)").Groups.Translate([System.Security.Principal.NTAccount])

PowerShell Version: 1
Modules: none

Get OS Name with PowerShell

16. April 2015

If you need the name of the operation system for any kind of filter use this:

(Get-WMIObject Win32_OperatingSystem).name


Result:
Microsoft Windows 7 Enterprise |C:\Windows|\Device\Harddisk0\Partition1

Possible filter for any kind of script:

$os = (Get-WMIObject Win32_OperatingSystem).name

if ($os -like "*Windows 7*")
    {
    }

PowerShell Version: 4
Modules: none

Get PowerShell version

If you want to get your major PowerShell version run the following:

$PSVersionTable.PSVersion.Major


Result:
4

PowerShell Version: 4
Modules: none

Find and remove disabled AD Users with PowerShell

If you have installed the “ActiveDirectory Module for Windows PowerShell” you can pretty easily handle every AD operation with PowerShell, like removing deactivated accounts for example:

Check for disabled users:

$users = Get-ADUser -Filter * | where {($_.enabled -eq $false)}

You can either measure

echo "COUNT:"
($users | measure).Count

or echo these users.

$user.UserPrincipalName

If you know want to remove those:

foreach ($user in $users)
    {
    Remove-ADUser -Identity $user.SAMAccountName
    $disabled = $user.UserPrincipalName
    "$disabled disabled."
    }

And the whole script:

$users = Get-ADUser -Filter * | where {($_.enabled -eq $false)}

echo "COUNT:"
($users | measure).Count

foreach ($user in $users)
    {
    Remove-ADUser -Identity $user.SAMAccountName
    $disabled = $user.UserPrincipalName
    "$disabled disabled."
    }

Update:
Since PowerShell 4 you can achieve this in one line:

Search-ADAccount -AccountDisabled | where {$_.ObjectClass -eq 'user'} | Remove-ADUser

PowerShell Version: 4
Modules: ActiveDirectory Module for Windows PowerShell

Remove Desktop items with PowerShell

If you want to remove Desktop items with PowerShell, this script will get the local Desktop folder from the registry and look for the item mentioned in line 5 to remove it (old shortcuts for example).

$desktopfolder = (Get-ItemProperty "hkcu:\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders").Desktop
$shortcuts = Get-Childitem $desktopfolder
foreach ($item in $shortcuts)
    {
        if ($item -match "example.lnk")
        { 
        Remove-Item $item.fullname
        echo "#########################################################################"
        echo $date 
        echo "$item from User $env:USERNAME at $env:COMPUTERNAME in $desktopfolder removed."
        }
    }

PowerShell Version: 4
Modules: none

Test Connection and Port with PowerShell

If the Test-Connection is just not enough you can also add a port check to your PowerShell scripts:

$ErrorActionPreference = 'SilentlyContinue' # we do not want to see any errors here

$hostip = "127.0.0.1"
$port = "4441"

Test-Connection $hostip -Count 2 | out-null
    if ([int]$? -eq 0)
    {
    echo "$hostip is offline!"
    }
    else
    {
    echo "$hostip is online!"
    $Socket = New-Object Net.Sockets.TcpClient
    $Socket.Connect($hostip, $port)
    $ErrorActionPreference = 'Continue'
    if ($Socket.Connected)
        {
        echo "-> $port is open!"
        $Socket.Close()
        }
    else
        {
        echo "-> $port is closed or filtered!"
        }
    }
    #resetting the variable between iterations is necessary.
    $Socket = $null

Line 14 to 28 is where the magic happens:

$hostip = "127.0.0.1"
$port = "4441"
$Socket = New-Object Net.Sockets.TcpClient
$Socket.Connect($hostip, $port)
$ErrorActionPreference = 'Continue'
if ($Socket.Connected)
    {
    echo "-> $port is open!"
    $Socket.Close()
    }
else
    {
    echo "-> $port is closed or filtered!"
    }
}
#resetting the variable between iterations is necessary.
$Socket = $null


Result:
127.0.0.1 is online!
-> 4441 is open!

PowerShell Version: 4
Modules: none

Clear temp folders on Computer start with PowerShell

This script will clear the common temp folders on Windows 7 client computers.

$date = Get-Date -Format "dd.mm.yy-HH:mm"
$win_temp_folder = "C:\Windows\Temp"
$outfile = "C:\tmp\clear_tmp.log"
$temp_folders = Get-Item C:\Users\*\AppData\Local\Temp
$os = (Get-WMIObject Win32_OperatingSystem).name

if ($os -like "*Windows 7*")
    {
    # CLEAR APPDATA LOCAL TEMP FOLDER PER USER
    foreach ($temp_folder in $temp_folders)
        {
        $user_temp_files = Get-ChildItem -Path $temp_folder
        $user_temp_files_count = ($user_temp_files | measure).Count
            if ($user_temp_files_count -gt 0)
            {
            echo "#########################################################################" | Out-File $outfile -Append
            echo "$date" | Out-File $outfile -Append
            $user_temp_folder_fullname = $temp_folder.FullName
            echo "Clearing $user_temp_folder_fullname" | Out-File $outfile -Append
            Remove-Item $user_temp_folder_fullname\* -Recurse -Force   
            }
        }
        # CLEAR WINDOWS TEMP FOLDER
        echo "Clearing $win_temp_folder" | Out-File $outfile -Append
        Remove-Item $win_temp_folder\* -Recurse -Force
    }

In line 4 we make sure to grab the \AppData\Local\Temp folder for every user on the machine and with line 7 we apply this to Windows 7 client PCs only. The script will write it’s activity in the $outfile.

I recommend applying this as a GPO start up script to make sure that none of the files in those folders are in use while the script runs: Computer-Configuration\Policies\Windows-Settings\Scripts\

PowerShell Version: 4
Modules: none

Monitoring a PING connection with PowerShell

This script will let you silently monitor a PING connection to 3 hosts. We apply this via GPO as a login script and it will monitor the user’s connection to those hosts and write connection losses to the outfile shown in line 4.

If a connection loss to one of the main hosts occurs we added 2 subhosts to check and see if the connection to the local gateway and filesever is OK.

$ErrorActionPreference= 'silentlycontinue'
$date_header = Get-Date -Format ddMMyy

$outfile = "PATHTOYOURLOG_$($env:USERNAME)_$($env:COMPUTERNAME)_$($date_header).log"
$host1 = "YOURHOST"
$host2 = "YOURHOST"
$host3 = "YOURHOST"
$sub_host1 = "YOURSUBHOST"
$sub_host2 = "YOURSUBHOST"
Get-Date -Format "dd.MM.yy HH:mm:ss" | Out-File $outfile -Append
echo "Starting script..." | Out-File $outfile -Append

        do
        {
        
        # HOST1
        Test-Connection $host1 -Count 4 | out-null
        if ([int]$? -eq 0)
            {
            $date = Get-Date -Format "HH:mm:ss"
            echo "########################################################" | Out-File $outfile -Append
            echo "$date Lost connection to $host1" | Out-File $outfile -Append
            # SUB-HOST1
            Test-Connection $sub_host1 -Count 1 | Out-File $outfile -Append
            # SUB-HOST2
            Test-Connection $sub_host2 -Count 1 | Out-File $outfile -Append
            }

        # HOST2
        Test-Connection $host2 -Count 4 | out-null
        if ([int]$? -eq 0)
            {
            $date = Get-Date -Format "HH:mm:ss"
            echo "########################################################" | Out-File $outfile -Append
            echo "$date Lost connection to Host $host2" | Out-File $outfile -Append
            # SUB-HOST1
            Test-Connection $sub_host1 -Count 1 | Out-File $outfile -Append
            # SUB-HOST2
            Test-Connection $sub_host2 -Count 1 | Out-File $outfile -Append
            }

        # HOST3
        Test-Connection $host3 -Count 4 | out-null
        if ([int]$? -eq 0)
            {
            $date = Get-Date -Format "HH:mm:ss"
            echo "########################################################" | Out-File $outfile -Append
            echo "$date Lost connection to $host3" | Out-File $outfile -Append
            # SUB-HOST1
            Test-Connection $sub_host1 -Count 1 | Out-File $outfile -Append
            # SUB-HOST2
            Test-Connection $sub_host2 -Count 1 | Out-File $outfile -Append
            }

        }
        while ($asd = 1)

PowerShell Version: 4
Modules: none

Next Page →