Modifying local accounts with powershell - windows

I'm trying to set the properties of a local account on a bunch of servers to "password never expires". This is the best I could figure out. I keep getting:
Get-WmiObject : Invalid parameter
At C:\Users\xxxxxx\AppData\Local\Temp\4f06fa1c-61da-4c65-ac0b-a4167d83d51c.ps1:4 char:14
+ Get-WmiObject <<<< -class Win32_UserAccount -Filter "name = 'localaccount'" - ComputerName $server | Set-WmiInstance -Argument #{PasswordExpires = 0}
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject], ManagementException
+ FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
--------- Here's what I am trying ------------
$servers = Get-Item c:\list.txt
foreach ($server in $servers)
{
Get-WmiObject -class Win32_UserAccount -Filter "name = 'localaccount'" -ComputerName $server | Set-WmiInstance -Argument #{PasswordExpires = 0}
}
Thank you!

Your mistake is in this line:
$servers = Get-Item c:\list.txt
The Get-Item cmdlet returns a FileInfo object, not the content of the file. For reading the content into a variable you need the Get-Content cmdlet.
This should work:
Get-Content 'c:\list.txt' | % {
gwmi Win32_UserAccount -Computer $_ -Filter "name='localaccount'" |
Set-WmiInstance -Argument #{PasswordExpires = $false}
}
You could also do the property change like this (source):
Get-Content 'c:\list.txt' | % {
$account = gwmi Win32_UserAccount -Computer $_ -Filter "name='localaccount'"
$account.PasswordExpires = $false
$account.Put()
}

Related

Reduce memory consumption by Powershell script

I'm using this Powershell script to retrieve info of remote servers from a central server.
In this case, there are about 150 servers on Active Directory:
$Servers = Get-ADComputer -Filter 'Name -like "...*"' | Select-Object -ExpandProperty Name
foreach ($computer in $Servers)
{
try
{
$ping = Test-Connection -ComputerName $computer -count 1 -ErrorAction Stop
$IP = ($ping.IPV4Address).IPAddressToString
$hardware = Get-CimInstance -Class Win32_ComputerSystem -ComputerName $computer -ErrorAction Stop
$totalMemory = (Get-CimInstance Win32_PhysicalMemory -ComputerName $computer | Measure-Object -Property capacity -Sum).sum /1gb
$os = Get-CimInstance -Class Win32_OperatingSystem -ComputerName $computer
$cpu = Get-CimInstance -Class Win32_processor -ComputerName $computer | Group-Object -Property Name |
Select-Object -Property Name,
#{Name = 'TotalSockets'; Expression = {$_.Count}},
#{Name = 'TotalCores'; Expression = {($_.Group | Measure-Object -Property NumberOfCores -Sum).Sum}},
#{Name = 'TotalLogicalProcessors'; Expression = {($_.Group | Measure-Object -Property NumberOfLogicalProcessors -Sum).Sum}}
#$disks = Get-WmiObject Win32_Volume -ComputerName $computer -Filter "DriveType='3'" | Sort-Object Name
# create new custom object to keep adding store information to it
$Result = New-Object -TypeName PSCustomObject -Property #{
ComputerName = $computer.ToUpper()
IPAddress = $IP
Manufacturer = $hardware.Manufacturer
Model = $hardware.Model
ADDescription = (Get-ADComputer -Identity $computer -Properties Description).Description -join ';'
ProductName = $os.Caption
OSVersion = $os.version
BuildNumber = $os.BuildNumber
OSArchitecture = $os.OSArchitecture
Domain = $hardware.Domain
'RAM (GB)' = $totalMemory
CPU = $cpu.Name
CPUTotalSockets = $cpu.TotalSockets
CPUTotalCores = $cpu.TotalCores
CPUTotalLogicalProcessors = $cpu.TotalLogicalProcessors
CPUVirtualizationFirmwareEnabled = (Get-CimInstance -Class Win32_processor -ComputerName $computer).VirtualizationFirmwareEnabled -join ','
}
# Column ordering, re-order if you like
<#$colOrder = 'ComputerName', 'IPAddress', 'Manufacturer', 'Model', 'ADDescription',
'ProductName', 'OSVersion', 'BuildNumber', 'OSArchitecture',
'Domain', 'RAM (GB)', 'CPU', 'CPUTotalSockets', 'CPUTotalCores',
'CPUTotalLogicalProcessors', 'CPUVirtualizationFirmwareEnabled'#>
# Return all your results
#$Result | Select-Object -Property $colOrder
$Result | Select-Object "ComputerName", "IPAddress", "Manufacturer", "Model", "ADDescription", "ProductName", "OSVersion", "BuildNumber",
"OSArchitecture", "RAM (GB)", "CPU", "CPUTotalSockets", "CPUTotalCores", "CPUTotalLogicalProcessors", "CPUVirtualizationFirmwareEnabled", "Domain" |
Export-Csv -Path "C:\SQL\Get-Inventory.csv" -Delimiter '|' -Append -NoTypeInformation
#$disks | Format-Table DriveLetter, Label, #{Name='Size(GB)'; Expression={[decimal]('{0:N0}' -f($_.Capacity/1gb))}}, #{Name='FreeSpace(GB)'; Expression={[decimal]('{0:N0}' -f($_.FreeSpace/1gb))}}
}
catch
{ Write-Output "--- $computer ---" $Error[0] `n | Add-Content -Path C:\SQL\UnreachableServers.txt }
}
The Powershell's process uses an average of 50/75 Mb of RAM. It's possible to reduce the RAM usage?
I accept any kind of advice given my little experience on Powershell :)
Thanks in advance.
Alessandro

Inventory Out-File with a new row

I have an Inventory Powershell script that I am trying to output into a csv. My goal is to output each execution of the script in a separate row going down their columns.
I've tried Export-Csv, but since i'm using variables, the csv displays (i'g guessing) metadata.
$ComputerName = Get-WmiObject Win32_OperatingSystem | select -ExpandProperty CSName
$OS_Name = Get-WmiObject Win32_OperatingSystem | Select-Object -ExpandProperty Caption
$OS_Architecture = Get-WmiObject Win32_OperatingSystem | select -ExpandProperty OSArchitecture
$System_Manufacturer = Get-WmiObject win32_computersystem | select -ExpandProperty Manufacturer
$Model = Get-WmiObject win32_computersystem | select -ExpandProperty Model
$CPU_Manufacturer = Get-WmiObject Win32_Processor | select -ExpandProperty Name
$Disk_Size_GB = Get-WmiObject win32_diskDrive | Measure-Object -Property Size -Sum | % {[math]::round(($_.sum /1GB),2)}
$Physical_Memory_GB = Get-WMIObject -class Win32_PhysicalMemory | Measure-Object -Property capacity -Sum | % {[Math]::Round(($_.sum / 1GB),2)}
$Version=(Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ReleaseId).ReleaseId
$InstallDate= systeminfo | find /I “Install Date”
$Assettag=(Get-WmiObject -Class Win32_SystemEnclosure | Select-Object SMBiosAssetTag).SMBiosAssetTag
$SerialNumber = (Get-WmiObject -Class Win32_BIOS | Select-Object SerialNumber).SerialNumber
($Assettag, $ComputerName, $System_Manufacturer, $Model, $OS_Name, $Version, $SerialNumber | Format-Table | Out-File C:\Users\1\Desktop\Newinvent.csv )
I expect each row to be filled with each execution
Thanks
If you want to use Export-Csv, you need to have an object with properties that contain the names and values you want to export. One way to do this is to create a [PSCustomObject] with all of your properties defined in a hash table. You can pipe that custom object to the Export-Csv command.
[PSCustomObject]#{"ComputerName" = $ComputerName
"OS_Name" = $OS_Name
"OS_Architecture" = $OS_Architecture
"System_Manufacturer" = $System_Manufacturer
"Model" = $Model
"CPU_Manufacturer" = $CPU_Manufacturer
"Disk_Size_GB" = $Disk_Size_GB
"Physical_Memory_GB" = $Physical_Memory_GB
"Version" = $Version
"InstallDate" = $InstallDate
"Assettag" = $Assettag
"SerialNumber" = $SerialNumber
} | Export-Csv -Path file.csv -NoTypeInformation -Append
And try to look at the result from Get-ComputerInfo - most of your needs are satisfied there.
I'd avoid the time consuming Systeminfo
> (Measure-Command {$systeminfo=(systeminfo) 2>$NULL}).Totalseconds
3,0428012
As well as Get-ComputerInfo
$OldProgressPreference = $ProgressPreference
$ProgressPreference = 'SilentlyContinue'
(Measure-Command {$ComputerInfo = Get-ComputerInfo}).Totalseconds
3,1837208
$ProgressPreference = $OldProgressPreference
And use an optimized version of your script which gets/converts InstallDate from registry:
> (Measure-Command{Q:\Test\2019\06\03\SO_56429703.ps1}).TotalSeconds
1,635074
Get-Content file.csv
## Q:\Test\2019\06\03\SO_56429703.ps1
function RoundGB($Size){
[math]::round(($Size/1GB),2)
}
$Win32OS = Get-WmiObject Win32_OperatingSystem
$Win32CS = Get-WmiObject Win32_ComputerSystem
$CurrVer = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
$InstDate= [timezone]::CurrentTimeZone.ToLocalTime([datetime]'1/1/1970').AddSeconds(
(Get-ItemProperty $CurrVer).InstallDate)
$inventory = [PSCustomObject]#{
ComputerName = $Win32OS.CSName
OSName = $Win32OS.Caption
OSArchitecture = $Win32OS.OSArchitecture
SystemManufacturer= $Win32CS.Manufacturer
Model = $Win32CS.Model
CPUManufacturer = (Get-WmiObject Win32_Processor).Name
DiskSizeGB = RoundGB (Get-WmiObject Win32_DiskDrive | Measure-Object Size -Sum).Sum
PhysicalMemoryGB = RoundGB (Get-WMIObject Win32_PhysicalMemory | Measure-Object capacity -Sum).Sum
Version = (Get-ItemProperty -Path $CurrVer -Name ReleaseId).ReleaseId
InstallDate = $InstDate
Assettag = (Get-WmiObject Win32_SystemEnclosure).SMBiosAssetTag
SerialNumber = (Get-WmiObject Win32_BIOS).SerialNumber
}
$Inventory | Export-Csv -Path file.csv -NoTypeInformation -Append

Delete domain profiles older than x days

i need some help in order to complete the script, i have already script which deleting specific profiles on the remote server, but i want o add time frame. Example: if the profile was not used for more than 120 days delete it.
Function Get-OldProfiles {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True,Position=1)] [string]$computerName
)
PROCESS {
foreach ($computer in $computerName) {
Write-host -ForegroundColor Yellow "Housekeeping on $computer"
Write-host -ForegroundColor Yellow "Mapping drive \\$computer\c$"
$drive = New-PSDrive -Name $computer.replace(".","-") -PSProvider FileSystem -Root \\$computer\C$
Write-host -ForegroundColor Yellow "Checking windows version"
#Cheking windows version
$version = (Get-WmiObject -ComputerName $computer -Class Win32_OperatingSystem).version
Write-host -ForegroundColor Yellow "Windows version $version"
#Profile Deleting area.
if ($version -ge 6) {
Write-host -ForegroundColor Yellow "Getting profiles from WMI"
$profiles = Get-WmiObject -ComputerName $computer Win32_UserProfile -filter "LocalPath Like 'C:\\Users\\%'" | Where-object localpath -Match 'B.{5}R$'| Select-Object {$_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-2)}
if ($profiles -ne $null) {
$profiles | foreach {
Write-host -ForegroundColor Red ("Deleting profile: " + $_.LocalPath)
#$_.Delete()
}
}
}
}
}
}
I've tried this:
$profiles= Get-WmiObject -ComputerName $computer -class Win32_UserProfile -filter "Special = False -and LocalPath Like 'C:\\Users\\%'" | Where-object localpath -Match 'B.{5}R$' | Where {$_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-120)}
But it returns an error
Get-WmiObject : Invalid query "select * from Win32_UserProfile where Special = False -and LocalPath Like 'C:\\Users\\%'"
At line:22 char:24 + $profiles= Get-WmiObject -ComputerName $computer -class Win32_UserPr ...
You can't use -and in a WQL-filter, it's just AND. Try:
$profiles = Get-WmiObject -ComputerName $computer -Class Win32_UserProfile -filter "Special = False AND LocalPath Like 'C:\\Users\\%'" |
Where-Object { ($_.localpath -Match 'B.{5}R$') -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-120)) }

Get Size, location and name of each shared folder

I have this code that generates a list of all the shares and the size however can not generate a txt with this information or the shared location
$servers = #("servername")
$sizes = #()
foreach($server in $servers) {
write-host "Server: $server"
(gwmi -class Win32_Share -ComputerName $server -filter "Type = 0" |
% {
write-host " share: $($_.Name)"
$s = gci \\$server\$($_.Name) -recurse -force | Measure-Object -Property length -Sum
New-Object PSObject -property #{Name=$_.Name; Server=$server; TotalSize=$s.Sum }
})
}
And this not only shows me the size and generates txt size and can generate txt
Get-WmiObject Win32_share -computer server01 | FT "server01", path, name > ServerShares.txt
Get-WmiObject Win32_share -computer server02 | FT "server02", path, name >> ServerShares.txt
Someone could help me to create only one that does everything
In your New-Object you just need to add additional properties to get the information you want:
If you're not running PowerShell v3, remove [Ordered]
$servers = #("servername")
$sizes = #()
foreach($server in $servers)
{
write-host "Server: $server"
# Get all shares
$shares = Get-WmiObject -class Win32_Share -ComputerName $server -filter "Type = 0"
# go through each share
foreach($share in $shares)
{
write-host " share: $($share.Name)"
# Get size of share
$size = Get-ChildItem -Path "\\$server\$($_.Name)" -recurse -force | Measure-Object -Property length -Sum
# Create a new object to store information
New-Object PSObject -property ([ordered]#{
# Name of share
Name = $share.Name
# Share path
Path = $share.path
# What server share is on
Server = $server
# Total size of share
TotalSize = $size.Sum
# Change this path to where you want the file to be saved to
}) | Export-Csv -Path C:\ShareDetails.csv -NoTypeInformation -Append
}
}
I made a small revision to #Bluecakes response in order to use COM instead of .NET to capture the size information. This overcomes the path-length issues.
# Get size of share
# $size = Get-ChildItem -Path "$($share.Name)" -recurse -force | Measure-Object -Property length -Sum
$objFSO = New-Object -com Scripting.FileSystemObject
$size = "{0:N2}" -f (($objFSO.GetFolder("$($share.Name)").Size) / 1MB)
Then you also need to remove ".sum"
# Total size of share
TotalSize = $size

Powershell determine the remote computer OS

I wrote a script to copy files to the "All Users" desktop or "Public Desktop"
However we have a mixed environment. Some people are using Windows XP and other people are using Windows 7.
$SOURCE = "I:\Path\To\Folder\*"
$DESTINATION7 = "c$\Users\Public\Desktop"
$DESTINATIONXP = "c$\Documents and Settings\All Users\Desktop"
$computerlist = Get-Content I:\Path\To\File\computer-list.csv
$results = #()
$filenotthere = #()
$filesremoved = #()
foreach ($computer in $computerlist) {
if((Test-Connection -Cn $computer -BufferSize 16 -Count 1 -ea 0 -quiet))
{
Write-Host "\\$computer\$DESTINATION\"
Copy-Item $SOURCE "\\$computer\$DESTINATION\" -Recurse -force
} else {
$details = #{
Date = get-date
ComputerName = $Computer
Destination = $Destination
}
$results += New-Object PSObject -Property $details
$results | export-csv -Path I:\Path\To\logs\offline.txt -NoTypeInformation -Append
}
}
DESTINATION is empty. Expanding on Keith's suggestion:
foreach ($computer in $computerlist) {
if((Test-Connection -Cn $computer -BufferSize 16 -Count 1 -ea 0 -quiet))
{
$OS = Get-WmiObject -Computer $computer -Class Win32_OperatingSystem
if($OS.caption -like '*Windows 7*'){
$DESTINATION = $DESTINATION7
}
if($OS.caption -like '*Windows XP*'){
$DESTINATION = $DESTINATIONXP
}
}
}
This could avoid the error you're getting also. empty $DESTINATION.
In your foreach loop through $computerlist you can grab the OS Caption for each computer by using WMI:
$OS = Get-WmiObject -Computer $computer -Class Win32_OperatingSystem
Ant then check the $OS
if($OS.caption -like '*Windows 7*'){
#Code here for Windows 7
}
#....
I had a slightly different goal...But thanks for the basics.
del C:\scripts\OS.csv
$computerlist = Get-Content c:\scripts\computerlist.csv
foreach ($computer in $computerlist) {
if((Test-Connection -Cn $computer -BufferSize 16 -Count 1 -ea 0 -quiet))
{
Get-WMIObject Win32_OperatingSystem -ComputerName $computer |
select-object CSName, Caption, CSDVersion, OSType, LastBootUpTime, ProductType| export-csv -Path C:\Scripts\OS.csv -NoTypeInformation -Append
}
}

Resources