Powershell script to deploy language during autopilot (based on choosed keyboard) - windows

So Alex Semibratov made a script that, based on the choice of the second (additional) keyboard, changes the language of the system to the one matching the keyboard language choice and sets everything as default. (Full localization of Windows 10/11 from Autopilot)
I came up with the idea that you can use the selection of the first keyboard (skipping the additional keyboard selection) which seems more obvious to the user. I found an entry in the registry where there is information about the keyboard language used:
$rpath = 'registry::HKEY_USERS\.DEFAULT\Keyboard Layout\substitutes'
$KB_lng_code = Get-Item -Path $rpath |select -ExpandProperty property | %{Get-ItemProperty $rpath | select -ExpandProperty $_}
$KB_lng_code
Switch ($KB_lng_code)
{
"0000040a" {Write-Host "es-es"}
"00000411" {Write-Host "ja-jp"}
"00000804" {Write-Host "zh-CN"}
"00000404" {Write-Host "zh-TW"}
}
I edited the first part of Alex script:
Start-Transcript -Path "$env:PROGRAMDATA\Localization.log" | Out-Null
$regpath = 'registry::HKEY_USERS\.DEFAULT\Keyboard Layout\substitutes'
$Languages = Get-Item -Path $regpath |select -ExpandProperty property | %{Get-ItemProperty $regpath | select -ExpandProperty $_}
if ($languages -eq "00000415") {$languages = 'pl-pl'}
elseif($languages -eq "0000040c") {$languages = 'fr-fr'}
elseif($languages -eq "00000816") {$languages = 'pt-pt'}
elseif($languages -eq "0000040a") {$languages = 'es-es'}
$Language = $languages
$inputLanguageID = $null
if ($language -eq $null)
{
$IPInfo = Invoke-RestMethod http://ipinfo.io/json
$Language = $IPInfo.country
}
$GeoID = (Get-ItemProperty -Path 'registry::HKEY_USERS\.DEFAULT\Control Panel\International\Geo').Nation
$LanguageExperiencePacklanguage = $Language
and the part with languages filled with the proper values: (example)
{$_ -eq "00000415" -or $_ -eq "pl-pl"} {
$applicationId = "9nc5hw94r0ld"
$GeoID = 191
$LanguageExperiencePacklanguage = "pl-PL"
if($inputLanguageID -eq $null) {$inputLanguageID = "0415:00000415"}
}
It finds the current keyboard language and installs the proper system language BUT I think it is kind of messy. Any ideas on how to make it better?
Regards

Related

Powershell: Find installed Antivirus & state, filtering out Windows Defender

I came across the basis of this script in another post here, however, I would like to take it a bit further and have been experimenting. What I am seeking to achieve is to get the name, state of the antivirus installed on the device and of course I want to filter out Windows Defender. Here is what I have so far...
The issue I have with the current code that I am not sure how to get around is that I am getting the state code for Windows Defender also.
I would greatly appreciate your advise and assistance.
clear
function Get-AntivirusName {
[cmdletBinding()]
param (
[string]$ComputerName = "$env:computername" ,
$Credential
)
$wmiQuery = "SELECT * FROM AntiVirusProduct"
$AntivirusProduct = Get-WmiObject -Namespace "root\SecurityCenter2" -Query $wmiQuery #psboundparameters
[array]$AntivirusNames = $AntivirusProduct.displayName | sort -unique
[array]$AntivirusState = $AntivirusProduct.productState | sort -unique
$AntivirusState
Switch($AntivirusNames) {
{$AntivirusNames.Count -eq 0}{"Anti-Virus is NOT installed!";Continue}
{$AntivirusNames.Count -eq 1 -and $_ -eq "Windows Defender"} {Write-host "ONLY Windows Defender is installed!";Continue}
{$_ -ne "Windows Defender"} {"Antivirus Product(s): $_."}
}
}
Get-AntivirusName
If you want to rule out Windows Defender, but do want to get a console message, I would change the function like below:
function Get-AntivirusName {
[cmdletBinding()]
param (
[string]$ComputerName = $env:COMPUTERNAME,
$Credential
)
$wmiQuery = "SELECT * FROM AntiVirusProduct"
$AntivirusProduct = #(Get-CimInstance -Namespace "root\SecurityCenter2" -Query $wmiQuery #psboundparameters)
if ($AntivirusProduct.Count -eq 0) {
Write-Host 'Anti-Virus is NOT installed!' -ForegroundColor Red
}
elseif ($AntivirusProduct.Count -eq 1 -and $AntivirusProduct.displayName -like '*Windows Defender*') {
Write-Host 'ONLY Windows Defender is installed!' -ForegroundColor Cyan
}
else {
# filter out Windows Defender from the list
$AntivirusProduct = $AntivirusProduct | Where-Object {$_.displayName -notlike '*Windows Defender*'} | Sort-Object -Unique
# output objects with both the product name and the status
foreach ($avProduct in $AntivirusProduct) {
[PsCustomObject]#{
AV_Product = $avProduct.displayName
AV_Status = $avProduct.productState
}
}
}
}
Get-AntivirusName

PowerShell 2 - Displaying Share Directory Where Everyone has Full Control

PowerShell Version: 2 (I understand the risks)
The following command outputs all shares where the "everyone" user group has access:
$Found = #()
Get-WmiObject win32_logicalsharesecuritysetting |
ForEach-Object {$Path = "\\localhost\\" + $_.Name; Get-Acl -Path $Path |
Select-Object Path -ExpandProperty Access |
ForEach-Object {If($_.IdentityReference -eq 'Everyone'){$Found += $_.Path}}}
Write-Host "Found: $($Found.Count)"
Write-Host "Share locations:"
$Found | ForEach-Object {Write-Host $_.Replace('Microsoft.PowerShell.Core\FileSystem::\\localhost\','')}
Can the command above be enhanced to only display shares where the "everyone" user group has "full control" only?
If the radio button is not selected, don't display anything in the output, however, if that full control radio button is selected for the user group "everyone", display an output:
so in my program i use this piece of code:
$Shares = Get-WmiObject -Class Win32_LogicalShareSecuritySetting
foreach($Share in $Shares) {
foreach($perm in $Permissions.Descriptor.DACL) {
if($Perm.Trustee.Name -eq "EveryOne" -and $Perm.AccessMask -eq "2032127" -and $Perm.AceType -eq 0) {
#EveryOneFullControl is true so do something
} else {
#EveryOneFullControl is false so do something
}
}
}

PowerShell terminate all RDP sessions of a user

I need a script that terminates all RDP sessions of an AD user.
Only the username should be given, whereupon the script terminates all RDP sessions of this user (if necessary also enforces them).
Unfortunately, the Get-RDUserSession cmdlet does not work (the ConnectionBroker cannot be found).
Unfortunately, I cannot process the result of the CMD command qwinsta in PowerShell.
Any ideas or tips?
Thank you.
You can create custom objects from qwinsta's output, filter them and use rwinsta to kill the session.
Function Get-TSSessions
{
param (
[Parameter(Mandatory = $true, Position = 0 )]
[String]$ComputerName
) # End Parameter Block
qwinsta /server:$ComputerName |
ForEach-Object{
If($_ -notmatch "SESSIONNAME")
{
New-Object -TypeName PSObject -Property `
#{
"ID" = [Int]$_.SubString(41,05).Trim()
"ComputerName" = $Computer
"User" = $_.SubString(19,22).Trim()
"State" = $_.SubString(47,08).Trim()
}
}
}
} # End Function Get-TSSessions
Get-TSSessions -ComputerName <ServerName> |
Where-Object{$_.User -eq "SomeUser"} |
ForEach{ & "rwinsta /Server:$($_.ComputerName) $($_.ID)" }
Obviously, you can improve by wrapping up the rwinsta command in its own function. At the moment I only have reporting work written around this sort of thing, so in the spirit of answering the question without writing the whole thing, this should get you through.
Also, I believe there are a number of scripts and functions available for this on the PowerShell Gallery. In fact, I think there were functions Get/Stop-TerminalSession in the PowerShell Community Extensions, which you can install as a module.
param
(
[Parameter(Mandatory = $false,
HelpMessage = 'Specifies the user name (SamAccountName).',
DontShow = $false)]
[SupportsWildcards()]
[ValidateNotNullOrEmpty()]
[ValidateScript({
Import-Module -Name 'ActiveDirectory' -Force
if (Get-ADUser -Filter "sAMAccountName -eq '$_'") {
return $true
} else {
return $false
}
})]
[string]$Username = $env:USERNAME
)
$ErrorActionPreference = 'SilentlyContinue'
Import-Module -Name 'ActiveDirectory' -Force
foreach ($system in (Get-ADComputer -Filter ("Name -ne '$env:COMPUTERNAME' -and OperatingSystem -like 'Windows Server*'"))) {
[string]$system = $system.Name
$session = ((quser /server:$system | Where-Object {
$_ -match $Username
}) -split ' +')[3]
if ($session) {
logoff $session /server:$system
}
}

Pattern as a input in powershell

I am trying a script that could compress and delete folders which is in 'n' sublevel folders.
For example the below script could do the job for 3 sublevel folders.
$path = Read-Host "Enter the path"
$directory = $path +"\*\*\*"
Add-Type -AssemblyName System.IO.Compression.FileSystem
$folders = Get-ChildItem $directory -recurse | Where-Object {$_.PSIsContainer -eq $true} | Select-object -ExpandProperty FullName
foreach ($folder in $folders) {
Write-Verbose "Archiving $archive"
$archive = $folder + '.zip'
[System.IO.Compression.ZipFile]::CreateFromDirectory($folder, $archive, 'Optimal', $True)
Remove-Item $folder -recurse -force -Verbose
}
The script is working fine...My doubt is, how to input the sublevel as a input value?
In the above script I am giving the path as a input...Likewise, I wish to input the sublevel also as a input value.
For example: Enter the level:3 (This should assume the pattern like (bs* bs* bs*)
or 4 (bs* bs* bs* bs*)
Note : I had mentioned \ as bs. Because if I mention the pattern as in script, its not visible in the preview.
Any help?
PowerShell allows you to replicate strings with its * operator:
PS> $numLevels = 3; $path = 'C:\path\to'; $path + ('\*' * $numLevels)
C:\path\to\*\*\*

PowerShell -Filters Failing on -notlike comparison

I have this script trying to pull inactive users from AD, but if someone doesn't have a Title, they don't get picked up. I tested the logic on an empty title for a single user, which returned as true, but when it runs through the foreach, it doesn't work (output shows only people with a Title are valid). I thought maybe the lastlogontimestamp comparison wasn't working so I added lastlogondate, but seems the Title is still the problem and I have no idea why?
#Inactivity Process
Import-Module ActiveDirectory
# Gets time stamps for all User in the domain that have NOT logged in since after specified date. Exludes Prism and PlanLink providers.
$DaysInactive = 365
$time = (Get-Date).Adddays(-($DaysInactive))
$Out_file = "C:\scripts\adcleanup\Inactivity-365days-or-longer_$((Get-Date).ToString('MM-dd-yyyy')).csv"
$Out_file2 = "C:\scripts\adcleanup\FailInactivity-365days-or-longer_$((Get-Date).ToString('MM-dd-yyyy')).csv"
# Get all AD User with lastLogonTimestamp less than our time and set to enabled. Check All Users for this...
$Users = Get-ADUser -Filter {samaccountname -like "s0*" -and (enabled -eq $true) -and (Title -notlike "*PRISM*") -and (Title -notlike "*PlanLink*") } -Properties samaccountname,name,enabled,Title,LastLogontimestamp, lastlogondate |
select SamAccountname,Name,Title,#{Name="LastLogonTimeStamp"; Expression={[DateTime]::FromFileTime($_.lastLogonTimestamp)}},lastlogondate, enabled
Foreach ($User in $Users) {
If (($user.LastLogontimestamp -le $time) -or ($user.LastLogondate -le $time)) {
$User| export-csv $Out_file -notypeinformation -append
}
Else {
$User | export-csv $Out_file2 -notypeinformation -append
}
}
I figured it out.
If (($user.LastLogontimestamp -le $time) -or ($user.LastLogondate -le $time) -or ($user.title -eq "") -and ($user.title -notlike "*PRISM*") -and ($User.title -notlike "*Planlink*") -and (!([string]::IsNullOrEmpty($user.lastlogondate)))) {

Resources