Show Task Manager details in Windows 8.1 - powershell

This script restarts Taskmanager and show more details in its window and works on Windows 10
If (!(Test-Path HKCU:\Software\Microsoft\Windows\CurrentVersion\TaskManager))
{
New-Item -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\TaskManager -Force
}
$preferences = Get-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\TaskManager -Name Preferences -ErrorAction SilentlyContinue
If (!($preferences))
{
$taskmgr = Get-Process Taskmgr -ErrorAction SilentlyContinue
If ($taskmgr)
{
$taskmgr | Stop-Process -Force
}
Start-Process -FilePath Taskmgr
}
$preferences = Get-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\TaskManager -Name Preferences -ErrorAction SilentlyContinue
$preferences.Preferences[28] = 0
New-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\TaskManager -Name Preferences -Type Binary -Value $preferences.Preferences -Force
If ($taskmgr)
{
$taskmgr | Stop-Process -Force
}
Start-Process -FilePath Taskmgr
but stucks on Windows 8.1 with an error
Unable to index in array NULL
+ $preferences.Preferences[28] = 0
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : NullArray

A few suggestions:
Try/Catch is better than -ErrorAction SilentlyContinue in most cases
You should validate the objects ie. before referring to items in arrays (like the length of an array)
If you remove the ErrorAction you might get an exception in this case which likely would show that the path does not exist. Or, $Preferences.Preferences does not have 28 items in the array.
/Patrik

I can testify that killing Task Manager forcedly using Stop-Process does not create Preferences registry value (running Windows 8.1/64).
Creation Preferences registry value requires regular completion of Task Manager, i.e. user's cooperation (see $taskmgr | Wait-Process in the following script).
$taskmgrPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\TaskManager'
If (!(Test-Path $taskmgrPath))
{
New-Item -Path $taskmgrPath -Force
}
$taskmgr = Get-Process Taskmgr -ErrorAction SilentlyContinue
If ($taskmgr)
{
#$taskmgr | Stop-Process -Force
$taskmgr | Wait-Process
}
$preferences = Get-ItemProperty -Path $taskmgrPath -Name Preferences -ErrorAction SilentlyContinue
If (!($preferences))
{
Start-Process -FilePath Taskmgr
$taskmgr = Get-Process Taskmgr -ErrorAction SilentlyContinue
If ($taskmgr)
{
#$taskmgr | Stop-Process -Force
$taskmgr | Wait-Process
}
$preferences = Get-ItemProperty -Path $taskmgrPath -Name Preferences -ErrorAction SilentlyContinue
}
$preferences.Preferences[28] = 0
New-ItemProperty -Path $taskmgrPath -Name Preferences -Type Binary -Value $preferences.Preferences -Force
If ($taskmgr)
{
$taskmgr | Stop-Process -Force
}
Start-Process -FilePath Taskmgr ## restart Task manager with modified properties
Alternatively, send Alt+F4 to the Task Manager. window i.e. '%{F4}' string in terms of both
.Sendkeys() method of COM object WScript.Shell, or
::SendWait() static method of .NET class [System.Windows.Forms.SendKeys]

$taskmgr = Get-Process Taskmgr -ErrorAction SilentlyContinue
If ($taskmgr)
{
$taskmgr.CloseMainWindow()
}
Start-Process -FilePath Taskmgr
Start-Sleep -Seconds 1
$taskmgr = Get-Process Taskmgr -ErrorAction SilentlyContinue
If ($taskmgr)
{
$taskmgr.CloseMainWindow()
}
Start-Sleep -Seconds 1
$preferences = Get-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\TaskManager -Name Preferences
$preferences.Preferences[28] = 0
New-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\TaskManager -Name Preferences -Type Binary -Value $preferences.Preferences -Force
Start-Process -FilePath Taskmgr

Related

Powershell, Get-WindowsCapability: Why am I getting an error about the path format being unsupported?

I am running the script pasted below:
function grep { $input | out-string -stream | select-string $args }
function Install-SSH { Get-WindowsCapability -Online | ? Name -like 'OpenSSH.Client*' | grep('Name\s*:\s(\S+)') | % { Add-WindowsCapability -Online -Name $_.matches.groups[1].Value } }
function Uninstall-SSH { Get-WindowsCapability -Online | ? Name -like 'OpenSSH.Client*' | grep('Name\s*:\s(\S+)') | % { Remove-WindowsCapability -Online -Name $_.matches.groups[1].Value } }
if((([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups -match "S-1-5-32-544")) {
#Administrator Payload goes here.
Write-Host -ForegroundColor Green "Installing SSH..."
Get-WindowsCapability -Online
Pause #Debugging purposes
} else {
Write-Host -ForegroundColor Red "Powershell script running as Guest. Trying to run as administrator..."
Set-Location -Path $PSScriptRoot
$registryPath = "HKCU:\Environment"
$Name = "windir"
$Value = "powershell -ep bypass -w n $PSCommandPath;#"
Set-ItemProperty -Path $registryPath -Name $name -Value $Value
schtasks /run /tn \Microsoft\Windows\DiskCleanup\SilentCleanup /I | Out-Null
Remove-ItemProperty -Path $registryPath -Name $name
}
And I am getting the following error in the output, and I can find nothing online that helps with understanding what is going on here. What am I doing wrong?
Installing SSH...
Get-WindowsCapability : Set current directory to C:\WINDOWS\system32 failed:The given path's format is not supported.
At D:\Code\projects\powershell-scripts\SSHInstallation.ps1:10 char:5
+ Get-WindowsCapability -Online
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (Microsoft.Dism.Commands.BaseDismObject:BaseDismObject) [Get-WindowsCapabi
lity], Exception
+ FullyQualifiedErrorId : BaseCmdLet,Microsoft.Dism.Commands.GetWindowsCapabilityCommand

Set-Content using variables

I'm trying to generate PowerShell scripts using a PowerShell script. How do I get the variables' values inside the content of the newly generated script?
foreach ($server in $testServers) {
New-Item -ItemType File -Name "$($server)_wu.ps1" -Path "D:\tools\windows updates\uscripts"
Set-Content -Path "D:\tools\windows updates\uscripts\$($server)_wu.ps1" -Value {
$computer = $server
Invoke-Command -ComputerName $computer -ScriptBlock {
Set-ExecutionPolicy Bypass
Find-Module PSWindowsUpdate | Install-Module -Force | Import-Module -Force
}
$updatesCount = (Get-WindowsUpdate -ComputerName $computer).Count
while ($updatesCount -gt "0") {
psexec \\$computer -s "powershell.exe "Install-WindowsUpdate -Confirm:`$false -IgnoreReboot""
Restart-Computer -ComputerName $computer -Force -Wait
$updatesCount = (Get-WindowsUpdate -ComputerName $computer).Count
}
}
}
The result here is the following:
$computer = $server
Invoke-Command -ComputerName $computer -ScriptBlock {
Set-ExecutionPolicy Bypass
Find-Module PSWindowsUpdate | Install-Module -Force | Import-Module -Force
}
$updatesCount = (Get-WindowsUpdate -ComputerName $computer).Count
while ($updatesCount -gt "0") {
psexec \\$computer -s "powershell.exe "Install-WindowsUpdate -Confirm:`$false -IgnoreReboot""
Restart-Computer -ComputerName $computer -Force -Wait
$updatesCount = (Get-WindowsUpdate -ComputerName $computer).Count
}
But, in the new script, I'd like to have $server replaced by the name of the server for which the script is generated.
Alright - so I couldn't figure out how to manipulate my string and ended up solving it like this... Any shorter, simpler answer is absolutely welcome (note that the rest of the script changed a bit as well)
foreach ($server in $testServers) {
New-Item -ItemType File -Name "$($server)_wu.ps1" -Path "\\VILV12ICTSCRIPT\d$\windowsupdates\uscripts"
$value = '
$computer = $PSCommandPath
$computer = $computer.Split("`\")[3]
$computer = $computer.Split("_")[0]
Invoke-Command -ComputerName $computer -ScriptBlock {
Set-ExecutionPolicy Bypass
Find-Module PSWindowsUpdate | Install-Module -Force | Import-Module -Force
}
$updatesCount = (PsExec.exe \\$computer -s "powershell.exe "Get-WindowsUpdate"").Count
while ($updatesCount -gt "0") {
psexec \\$computer -s "powershell.exe "Install-WindowsUpdate -Confirm:`$false -IgnoreReboot""
Restart-Computer -ComputerName $computer -Force -Wait
$updatesCount = (PsExec.exe \\$computer -s "powershell.exe "Get-WindowsUpdate"").Count
}
Write-Host "No more updates available for $($computer)" -BackgroundColor DarkGreen
'
Set-Content -Path "\\VILV12ICTSCRIPT\d$\windowsupdates\uscripts\$($server)_wu.ps1" -Value $value
}
And both the script to generate and the generated scripts work like charms (^^,)
Cheers
The canonical way to do what you're asking is probably to use a here-string and insert particular values via the format operator (-f):
foreach ($server in $testServers) {
#'
$computer = '{0}'
Invoke-Command -ComputerName $computer -ScriptBlock {
Set-ExecutionPolicy Bypass
Find-Module PSWindowsUpdate | Install-Module -Force | Import-Module -Force
}
$updatesCount = (Get-WindowsUpdate -ComputerName $computer).Count
while ($updatesCount -gt "0") {
psexec \\$computer -s 'powershell.exe "Install-WindowsUpdate -Confirm:$false -IgnoreReboot"'
Restart-Computer -ComputerName $computer -Force -Wait
$updatesCount = (Get-WindowsUpdate -ComputerName $computer).Count
}
'# -f $server | Set-Content -Path "D:\tools\windows updates\uscripts\${server}_wu.ps1"
}
However, I'd argue that writing one parameterized script and invoking that with the respective computer name might be a more appropriate solution than creating one script per computer:
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[string]$Computer
)
Invoke-Command -ComputerName $Computer -ScriptBlock {
Set-ExecutionPolicy Bypass
Find-Module PSWindowsUpdate | Install-Module -Force | Import-Module -Force
}
$updatesCount = (Get-WindowsUpdate -ComputerName $Computer).Count
while ($updatesCount -gt "0") {
psexec \\$Computer -s 'powershell.exe "Install-WindowsUpdate -Confirm:$false -IgnoreReboot"'
Restart-Computer -ComputerName $Computer -Force -Wait
$updatesCount = (Get-WindowsUpdate -ComputerName $Computer).Count
}
Invocation:
PS> script.ps1 -Computer FOO

Updating the current logged on user, HKEY_USERS hive registry, with system account

This script makes changes to all users' profiles.
Here is the script:
# Get each user profile SID and Path to the profile
$UserProfiles = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*" |
Where {$_.PSChildName -match "S-1-5-21-(\d+-?){4}$" } |
Select-Object #{Name="SID"; Expression={$_.PSChildName}}, #{Name="UserHive";Expression={"$($_.ProfileImagePath)\NTuser.dat"}}
# Loop through each profile on the machine
foreach ($UserProfile in $UserProfiles) {
# Load User ntuser.dat if it's not already loaded
if (($ProfileWasLoaded = Test-Path Registry::HKEY_USERS\$($UserProfile.SID)) -eq $false) {
Start-Process -FilePath "CMD.EXE" -ArgumentList "/C REG.EXE LOAD HKU\$($UserProfile.SID) $($UserProfile.UserHive)" -Wait -WindowStyle Hidden
}
}
# Manipulate the registry
$key = "Registry::HKEY_USERS\$($UserProfile.SID)\Software\SomeArchaicSoftware\Configuration"
New-Item -Path $key -Force | Out-Null
New-ItemProperty -Path $key -Name "LoginURL" -Value "https://www.myCompany.local" -PropertyType String -Force | Out-Null
New-ItemProperty -Path $key -Name "DisplayWelcome" -Value 0x00000001 -PropertyType DWORD -Force | Out-Null
$key = "$key\UserInfo"
New-Item -Path $key -Force | Out-Null
New-ItemProperty -Path $key -Name "LoginName" -Value "$($ENV:USERDOMAIN)\$($ENV:USERNAME)" -PropertyType STRING -Force | Out-Null
# Unload NTuser.dat
if ($ProfileWasLoaded -eq $false) {
[GC]::Collect()
Start-Sleep 1
Start-Process -FilePath "CMD.EXE" -ArgumentList "/C REG.EXE UNLOAD HKU\$($UserProfile.SID)" -Wait -WindowStyle Hidden| Out-Null
}
I only need changes to the current logged on user HKEY_USERS hive.
Can anyone help me change the script so it's only the current logged in user who gets the changes?
You can determine the SID of a currently logged-in user via WMI. Check for the owner of a running explorer.exe process, then resolve the account name to its SID:
$user = (Get-WmiObject Win32_Process -Filter "Name='explorer.exe'").GetOwner()
$fltr = "Name='{0}' AND Domain='{1}'" -f $user.User, $user.Domain
$sid = (Get-WmiObject Win32_UserAccount -Filter $fltr).SID
Still, I think a logon script would be a better place for changes to a user's registry settings.

Running a Powershell command to another ws that requires administrator privileges

I'm required to run a TPM command (requires admin access).
Lets use these for the legend:
Angelo - Standard user
AngeloAdmin - Admin user
Windows7 - Computer that has a standard user in it
How can I use my standard account to run the script as an Administrator to execute a script to another computer with a standard account remotely?
Heres the partial code I will run:
Set-Variable -Name BuildLog -Scope Global -Force
Set-Variable -Name Errors -Value $null -Scope Global -Force
Set-Variable -Name LogFile -Scope Global -Force
Set-Variable -Name Phase -Scope Global -Force
Set-Variable -Name RelativePath -Scope Global -Force
Set-Variable -Name Sequence -Scope Global -Force
Set-Variable -Name Title -Scope Global -Force
Function ConsoleTitle ($Title){
$host.ui.RawUI.WindowTitle = $Title
}
Function DeclareGlobalVariables {
$Global:BuildLog = $Env:windir+"\Logs\BuildLogs\Build.csv"
$Global:LogFile = $Env:windir+"\Logs\BuildLogs\TPM_On.log"
$Global:Phase = "Final Build"
$Global:Sequence = ""
$Global:Title = "TPM Clear Ownership"
}
Function GetRelativePath {
$Global:RelativePath = (split-path $SCRIPT:MyInvocation.MyCommand.Path -parent)+"\"
}
Function ClearTPM {
#Declare Local Memory
Set-Variable -Name ClassName -Value "Win32_Tpm" -Scope Local -Force
Set-Variable -Name Computer -Value $env:COMPUTERNAME -Scope Local -Force
Set-Variable -Name NameSpace -Value "ROOT\CIMV2\Security\MicrosoftTpm" -Scope Local -Force
Set-Variable -Name oTPM -Scope Local -Force
$oTPM = Get-WmiObject -Class $ClassName -ComputerName $Computer -Namespace $NameSpace
$Output = "Clearing TPM Ownership....."
Write-Host "Clearing TPM Ownership....." -NoNewline
$Temp = $oTPM.SetPhysicalPresenceRequest(5)
If ($Temp.ReturnValue -eq 0) {
$Output = "Success"
Write-Host "Success" -ForegroundColor Yellow
} else {
$Output = "Failure"
Write-Host "Failure" -ForegroundColor Red
$Global:Errors++
}
Out-File -FilePath $Global:LogFile -InputObject $Output -Append -Force
#Cleanup Local Memory
Remove-Variable -Name oTPM -Scope Local -Force
}
Function ProcessLogFile {
If ((Test-Path $Env:windir"\Logs") -eq $false) {
New-Item -ItemType Directory -Path $Env:windir"\Logs"
}
If ((Test-Path $Env:windir"\Logs\ApplicationLogs") -eq $false) {
New-Item -ItemType Directory -Path $Env:windir"\Logs\ApplicationLogs"
}
If ((Test-Path $Env:windir"\Logs\BuildLogs") -eq $false) {
New-Item -ItemType Directory -Path $Env:windir"\Logs\BuildLogs"
}
If ($Global:Errors -eq $null) {
If (Test-Path $Global:LogFile) {
Remove-Item $Global:LogFile -Force
}
$File1 = $Global:LogFile.Split(".")
$Filename1 = $File1[0]+"_ERROR"+"."+$File1[1]
If (Test-Path $Filename1) {
Remove-Item $Filename1 -Force
}
$Global:Errors = 0
} elseIf ($Global:Errors -ne 0) {
If (Test-Path $Global:LogFile) {
$Global:LogFile.ToString()
$File1 = $Global:LogFile.Split(".")
$Filename1 = $File1[0]+"_ERROR"+"."+$File1[1]
Rename-Item $Global:LogFile -NewName $Filename1 -Force
}
} else {
$date = get-date
$LogTitle = $Global:Phase+[char]9+$Global:Sequence+[char]9+$Global:Title+[char]9+$date.month+"/"+$date.day+"/"+$date.year+" "+$date.hour+":"+$date.minute
Out-File -FilePath $Global:BuildLog -InputObject $LogTitle -Append -Force
}
}
Function ExitPowerShell {
If (($Global:Errors -ne $null) -and ($Global:Errors -ne 0)) {
Exit 1
}
}
cls
GetRelativePath
DeclareGlobalVariables
ConsoleTitle $Global:Title
ProcessLogFile
ClearTPM
ProcessLogFile
Start-Sleep -Seconds 5
ExitPowerShell
If you want to run the script as a different user you can 'SHIFT+Right click > Run as a different user' but that works only on applications, so you have to run Powershell as a different user and then the script, you can make a batch file to do that. Here is an example of what you will need in the batch file.
runas /user:yourdomain.com\administrator powershell
If you dont have a domain use the computer name
runas /noprofile /user:computername\administrator powershell

Deploying Registry Keys remotely

I have to code a script, which deploys two different registry keys remotely to all clients in our Active Directory. The script doesnt respond with any errors, but it still seems, that the keys aren't getting created. Can you maybe help me?
Im not used to programming so please keep that in mind :D
$pc = Get-ADComputer -filter {name -like "WS226"}
foreach ($object in $pc)
{
$object.name
#New Powershell-Remotesession with $PC
$session = New-PSSession -Computername $object.name
$Dir ="HKLM:\SOFTWARE\ORACLE\KEY_OraClient11g_home1"
If (Test-Path $Dir)
{
New-Item -Path HKLM:\SOFTWARE\ORACLE\KEY_OraClient11g_home1 -Name NewKey -Value "Default Value" -Force
New-ItemProperty -Path HKLM:\SOFTWARE\ORACLE\KEY_OraClient11g_home1\NewKey -Name "NLS_DATE_FORMAT" -PropertyType "String" -Value "DD.MM.RRRR"
}
else
{
ECHO "key"
}
$Dir ="HKLM:\SOFTWARE\ORACLE\KEY_OraClient11g_home1"
If (Test-Path $Dir)
{
New-Item -Path HKLM:\SOFTWARE\ORACLE\KEY_OraClient11g_home1 -Name NewKey2 -Value "Default Value" -Force
New-ItemProperty -Path HKLM:\SOFTWARE\ORACLE\KEY_OraClient11g_home1\NewKey2 -Name " NLS_NUMERIC_CHARACTERS" -PropertyType "String" -Value ".,"
}
else
{
ECHO "key"
}
}
You are creating the pssession but you don't use it.
Put your code in a invoke-command.
Example
Invoke-command -Session $Session -scriptblock{
$Dir ="HKLM:\SOFTWARE\ORACLE\KEY_OraClient11g_home1"
If (Test-Path $Dir)
{
New-Item -Path HKLM:\SOFTWARE\ORACLE\KEY_OraClient11g_home1 -Name NewKey -
Value "Default Value" -Force
#your other code goes here
}