Powershell script Memory usage - powershell

I'm running a simple script to get all inactive users (enabled state) not logged in for 60 days as below. The script seems to work fine on my workstation with ARS 6.7 & WinXP . But if i run the same script on another workstation with ARS 6.9 & Win7 the RAM usage of the script goes on increasing over time & it finally throws OutofMemory exception (after reaching 1.5+ GB) & aborts. The same script when run on WinXP workstation (ARS v6.7) does not consume more than 50 MB of RAM throughout. The domain i'm scanning is pretty big with over 550000 accounts. I'm totally confused about the issue here...Pls help!
[datetime]$TodayDate = Get-Date
[datetime]$InActivityDate = $TodayDate.AddDays(-62).Date
try
{
Get-QADUser -SearchRoot $SearchOU -Service $Service -SizeLimit $SizeLimit -PageSize 1000 -Enabled -DontUseDefaultIncludedProperties -IncludedProperties SamAccountName,`
Name,ParentContainer,DN,LastLogon,WhenCreated,PasswordLastSet,employeeID,`
employeeNumber,Manager,AccountIsDisabled,co,scriptPath |`
#Filter out inactive accounts
Where-Object {$_.LastLogonTimeStamp -lt $InActivityDate} |`
Select-Object SamAccountName,Name,ParentContainer,DN,LastLogon,WhenCreated,`
PasswordLastSet,employeeID,employeeNumber,Manager,`
AccountIsDisabled,co,scriptPath | Export-Csv $OutputFile -NoTypeInformation
}
catch
{
$ErrorMessage = $_.Exception.Message
$ErrTime = Get-Date
Write-Host "Error occured:`n$ErrorMessage" -ForegroundColor Red
Write-Output "[$ErrTime] Error occured:`n$ErrorMessage" | Out-File $OutputFile -Append
}

You should delegate filtering to AD side, quoting from Get-ADUser help: Get-ADUser -filter { lastLogon -le $logonDate } In your case, Get-QADUser cannot delegate filtering, so swap to Microsoft's AD module: Get-ADUser -filter { lastLogon -le $InactivityDate }. To get the module, install RSAT for oyur Windows version, then (if not enabled by default) go "Add/remove Windows components - RSAT - Role administration services - AD/LDAP - Windows Powershell module" and enable it.

Launching the Quest Shell in MTA mode has solved this problem. This can simply be done by adding "-mta" parameter to existing shortcut.
eg.
C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe
-psconsolefile "C:\Program Files\Quest Software\Management Shell for AD\ConsoleSettings.psc1" -noexit -Mta -command ". 'C:\Program
Files\Quest Software\Management Shell for AD\qsft.ps1'"

Related

Use PowerShell to install Windows Updates in vSphere

I have a cluster of vSphere windows clients approximately 100 that I want to remotely automate windows updates on weekly. I have listed all the windows machine out in text file on my desktop. I have run the PSWindowsUpdate module on my local windows10 machine with command:
Install-Module -Name PSWindowsUpdate and then executed the below script successful for my local machine to run windows updates.
#Import-Module PSWindowsUpdate
#Remove-Item -Path C:\Scripts\status.tx
#Start-Transcript -Path C:\Scripts\status.txt
#$Updates = "Critical Updates", "Security Updates"
#Get-WUInstall -AcceptALL- Verbose -IgnoreReboot -Category $Updates
#Write-Host "Done"
#Stop-Transcript
#Start-Sleep -s 120
#Restart-Computer -Force -Confirm:$false
-- after pc restarts run as PS As Administrator
#Get-WindowsUpdate
However, I am not a expert at PowerShell so, I do not know what to additionally script to accomplish the task of remotely updating 100 or so windows clients in vSphere.
Any suggestion would be appreciated.
You can try with the invoke-command. You can create a server list from a DC:
$Servers = Get-ADObject -Filter * -Properties Name,OperatingSystem | Where-Object OperatingSystem -like '*Server*'
And use this list with a loop like this
ForEach($_ in $Servers)
{
Invoke-Command -ScriptBlock {Get-WUInstall -AcceptALL- Verbose -IgnoreReboot -Category $Updates } -ComputerName $_.Name -ErrorAction SilentlyContinue
}

Powershell appears to run statements asynchronously? [duplicate]

This question already has answers here:
PowerShell output is crossing between functions
(1 answer)
weird delay of the output of an object when followed by start-sleep (or until script end)
(3 answers)
Closed 2 years ago.
I wrote a powershell cmdlet that works great on Server 2012 R2 (powershell 4.0), however on Windows 10 or Server 2016 (powershell 5.1) the commands do not appear to wait for each other to finish, but rather execute asynchronously (?). This is certainly not desired behavior and is causing the cmdlet to not function as intended.
The core of the script starts a transcript, runs Get-ADPrincipalGroupMembership followed by Get-ADUser and then Get-Date, and finally closes the transcript.
try {
Start-Transcript -Path $transactionFilename
Write-Host "GROUP MEMBERSHIP FOR $($targetUsername)"
Get-ADPrincipalGroupMembership -Credential $credential -Identity $Username -Server $domainServer | select name,distinguishedName | format-table
Write-Host "ACCOUNT PROPERTIES FOR $($targetUsername)"
Get-ADUser -Credential $credential -Identity $Username -Server $domainServer -Properties *
Write-Host "CURRENT TIME"
(Get-Date).DateTime
} catch {
} finally {
Stop-Transcript
write-host "Transcript is available at"
write-host $transactionFilename
$Host.UI.RawUI.BufferSize = New-Object Management.Automation.Host.Size ($originalHostWidth, $hostHeight)
}
When run on PS 4.0 each statement is executed in order - each one waiting for the previous to finish.
👍
When run on PS 5.1 the Get-ADPrincipalGroupMembership finishes, then the Write-Host "ACCOUNT PROPERTIES" runs then Write-Host "CURRENT TIME" runs, then everything in the finally block runs then the Get-ADUser and Get-Date commands run.
👎
As you can imagine, having Stop-Transcript run in the middle of the script is a show-stopper!
I've Googled for stopping a cmdlet from executing asynchronously, but all the articles are about how to make it execute async - not how to stop it. I'm not sure where to look for help now.
How can I adjust powershell 5.1 to run the statements synchronously? Backwards compatibility with 4.0 is not strictly necessary, but would be a bonus.
Per comments from #Lee_Dailey and #js2010 I was able to modify the script to function as desired by piping the output from format-table and Get-ADUser to Out-Host:
try {
Start-Transcript -Path $transactionFilename
Write-Host "GROUP MEMBERSHIP FOR $($targetUsername)"
Get-ADPrincipalGroupMembership -Credential $credential -Identity $Username -Server $domainServer | select name,distinguishedName | format-table | out-host
Write-Host "ACCOUNT PROPERTIES FOR $($targetUsername)"
Get-ADUser -Credential $credential -Identity $Username -Server $domainServer -Properties * | out-host
Write-Host "CURRENT TIME"
(Get-Date).DateTime
} catch {
} finally {
Stop-Transcript
write-host "Transcript is available at"
write-host $transactionFilename
$Host.UI.RawUI.BufferSize = New-Object Management.Automation.Host.Size ($originalHostWidth, $hostHeight)
}

PowerShell script that Changes a computer name based on the current IP address and lookup from a CSV file

We have a large effort underway for specific PC’s (approximately 10,000) that need to be renamed. They are in workgroup mode (not domain joined). Obviously if we can script this and do it remotely we should. I have been trying to better understand PowerShell and think it can actually be done pretty easily if I can get the code right. I need a very simple script that will:
Get the current IP address of the machine.
Compare that IP address to a CSV formatted list.
From the list, use the new Computer Name based on the IP Address and rename the computer.
The CSV would be very simple:
IPADDRESS,NEWCOMPNAME
192.168.0.1,NewPC1
192.168.0.2,NEWPC2
192.168.0.3,NEWPC3
This is the script I have so far but is not working:
$currentIpAddress = Test-Connection $env:COMPUTERNAME -count 1 | select Address, Ipv4Address
$csv = Import-Csv C:\test.csv
$newComputerName = $csv | where {$_.IPADDRESS -eq $currentIpAddress} | % NEWCOMPNAME
Rename-Computer -newname $newComputerName -Force -Restart
Thanks all for your comments and questions. I figured it out. Just to answer the questions and post the correct code for others, here goes. I am hitting Windows 8.1 x64 and Windows 10 x64. Powershell 4 and 5. If the computer name is not in the list, then the script fails (which is good) and does nothing. Also, we are running this as the local admin account, so the tests have proven successful so far.
The updated scripts are:
The CMD we are using:
If Not Exist C:\Temp MD C:\Temp
Copy /Y "%~dp0RenameComputerBasedOnIPList.csv" C:\temp\RenameComputerBasedOnIPList.csv
powershell -ExecutionPolicy ByPass -File "%~dp0RenameComputerBasedOnIPList.ps1"
The PowerShell script that is running:
Set-ExecutionPolicy -ExecutionPolicy Unrestricted
$currentIpAddress = Test-Connection $env:COMPUTERNAME -count 1 | select Address, Ipv4Address
$csv = Import-Csv C:\Temp\RenameComputerBasedOnIPList.csv
$newComputerName = $csv | where {$_.IPADDRESS -eq $currentIpAddress.IPV4Address} | % NEWCOMPNAME
Write-Host $currentIpAddress
Write-Host $csv
Write-Host $newComputerName
Rename-Computer -NewName $newComputerName -Force -Restart
The formatted list is like this named RenameComputerBasedOnIPList.csv.
IPADDRESS,NEWCOMPNAME
10.96.21.121,BADCOMPNAME
10.96.21.158,WIN10NAMECHANGE
192.168.0.2,BADCOMPNAME1
10.96.21.52,WIN81NAMECHANGE
Thanks again.

How to disable touch screen of laptops using PowerShell script?

My clients are using "HP Elitebook 840" touch screen laptop and recently we launched a website for their service, unfortunately click events on buttons did not worked in the web site. After a long R&D we realized it was touch screen issue and mouse click events started working after disabling it.
More info here: Click events are not working in Chrome, but event fires when we execute it manually from console
Since there are more than 40 users having same touch screen laptops, we would like to run a script to disable the touch feature of these laptops. I think network admin needs to run powershell script to do it, but I could not figure it out how to write single script to disable the touch screen of systems
I was reading http://www.surfaceforums.net/threads/disable-the-touch-screen-to-use-the-pen.12338/ but since I am new to PowerShell so need more detailed steps.
Powershell nuggets to disable/enable laptop touch screen. Tested in Windows 10 on Asus UX 501. Run as administrator.
Get-PnpDevice | Where-Object {$_.FriendlyName -like '*touch screen*'} | Disable-PnpDevice -Confirm:$false
Get-PnpDevice | Where-Object {$_.FriendlyName -like '*touch screen*'} | Enable-PnpDevice -Confirm:$false
(Source)
Use this in PowerShell:
Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Wisp\Touch -Name TouchGate -Value 0 -Type DWord
Restart machine after.
You can use the following registry key to disable touch input (requires a reboot):
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wisp\Touch]
"TouchGate"=dword:00000000
Or with PowerShell:
Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Wisp\Touch ompany -Name TouchGate -Value 0 -Type DWord
After some trial and error, I decided the best thing for me was to save two .bat files to handle this so that I could easily launch it using Launchy. Code below - you might need to add in logic to for the ExecutionPolicy based on your configuration, but works for me as written.
Copy this into notepad and save it as a .bat - just switch out "Disable" for "Enable" and you're good to go either direction
#ECHO off
Powershell.exe -Command "& {Start-Process Powershell.exe -ArgumentList '-Command ""& {Get-PNPDevice | Where-Object FriendlyName -Like ''*touch screen*'' | Disable-PNPDevice -Confirm:$false} ; Get-PNPDevice | Where-Object FriendlyName -Like ''*touch screen*'' ; if ($Host.Name -eq ''ConsoleHost'') {Write-Host ''Press any key to continue...'' ; $Host.UI.RawUI.FlushInputBuffer() ; $Host.UI.RawUI.ReadKey(''""NoEcho,IncludeKeyUp''"") > $null}""' -Verb RunAs}"
I found this question and saw the answers, which are good. However, I found that I didn't want two different scripts to enable/disable the touch screen. I wanted to have it under one to just toggle it's state, so I wrote this script:
# To allow script to be executed on double click
# https://stackoverflow.com/a/30644946/1366368
# To sign script
# https://adamtheautomator.com/how-to-sign-powershell-script/
# To automatically elevate script to admin privs, I used this code fromn https://superuser.com/a/532109/222708
param([switch]$Elevated)
function Test-Admin {
$currentUser = New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent())
$currentUser.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
}
if ((Test-Admin) -eq $false) {
if ($elevated) {
# tried to elevate, did not work, aborting
} else {
# Removed -noexit as it will force the powershell instance to keep running after finishing
Start-Process powershell.exe -Verb RunAs -ArgumentList ('-noprofile -file "{0}" -elevated' -f ($myinvocation.MyCommand.Definition))
}
exit
}
# If Status of touch screen is Error, then it is off.
$result = (Get-PnpDevice|Where-Object {$_.FriendlyName -like '*touch screen*'}|Select -ExpandProperty 'Status')
if ($result -eq 'Error') {
Write-Host "Enabling touch screen"
Get-PnpDevice|Where-Object {$_.FriendlyName -like '*touch screen*'}|Enable-PnpDevice -Confirm:$false
} else {
Write-Host "Disabling touch screen"
Get-PnpDevice|Where-Object {$_.FriendlyName -like '*touch screen*'}|Disable-PnpDevice -Confirm:$false
}

Finding current logged on user(s) while running as SYSTEM (no environment variables)

I have created a PowerShell script that saves the current user to a report. When creating this report, it was working fine because I was using $env:USERNAME. However, now that the report is running under the SYSTEM account as a scheduled task, it saves the current user as "HOSTNAME$." Is there another easy way of getting the logged on users? The following doesn't work as well:
Get-WMIObject -class Win32_ComputerSystem | select username
Any ideas would be greatly appreciated as I need the current logged on user saved. I also need to run the report as NT AUTHORITY\SYSTEM to run the elevated tasks.
"Current user" is an ambiguous term that depends on what you're looking at. A user logged in on the desktop (locally or remotely)? A user running a background process? A user accessing an SMB share? WMI? WinRS?
Assuming that you want to identify which user is logged in on the desktop, you could check the owner of the explorer.exe process as described in this answer on ServerFault:
Get-WmiObject Win32_Process -Filter "Name='explorer.exe'" |
ForEach-Object { $_.GetOwner() } |
Select-Object -Unique -Expand User
I was able to gather the current logged on user by using tasklist in PowerShell:
$User = tasklist /v /FI "IMAGENAME eq explorer.exe" /FO list | find "User Name:"
$User = $User.Substring(14)
Works perfectly even when ran as SYSTEM.
I know this is old, it took me all morning to get this straightened out, this gets you the current logged on user and their my docs path, since environment variables don't work under the system account.
New-PSDrive HKU Registry HKEY_USERS
$user = get-wmiobject -Class Win32_Computersystem | select Username;
$sid = (New-Object System.Security.Principal.NTAccount($user.UserName)).Translate([System.Security.Principal.SecurityIdentifier]).value
$val = (Get-Item "HKU:\$sid\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders");
$myDocPath = $val.GetValue("Personal");
To test using a powershell account that runs as system, follow these instructions
http://powershell-guru.com/powershell-tip-53-run-powershell-as-system/
Assuming from your original script that you are looking to return just usernames, you could use this:
Get-Process -IncludeUserName | Select-Object UserName -Unique |
Where-Object {$.UserName -notlike 'NT AUTHORITY\SYSTEM' -and
$.UserName -notlike 'NT AUTHORITY\NETWORK SERVICE' -and $_.UserName
-notlike 'NT AUTHORITY\LOCAL SERVICE'} | Format-Table -Wrap -AutoSize
I liked the Get-Process answer from #MNiles, but made it a little simpler with the filtering for explorer from the other answers
Get-Process -IncludeUserName -Name explorer | Select-Object UserName -Unique