Get device serial number with PowerShell

27. May 2015

ps

PowerShell Version: >2
Modules: none

This will print the serial number of your device:

(gwmi win32_bios | select SerialNumber).serialNumber

or

gwmi win32_bios | Select –ExpandProperty SerialNumber

DFS namespace access denied error while UNC path to server works fine

22. May 2015

Today I had an interesting issue with DFS shares. I created a new user which was not able to access the DFS share via FQDN (\\domain\dfsspace\sharename) but was able to access the UNC path (\\servername\sharename).

After some research I found out that the DFS cache sometimes creates this issue and needs to be wiped before proceeding. There are two ways to handle this:

Enter this in an elevated command prompt on the client and reboot:

reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Csc\Parameters /v FormatDatabase /t REG_DWORD /d 1 /f

Or as an alternative create a new .reg file containing this, execute on the client and reboot:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\CSC\Parameters]
"FormatDatabase"=dword:00000001

 

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

← Previous Page
Next Page →