Powershell, WMI and compressed files/folders - powershell

I need to generate a script that will help me in getting a list of compressed files/folders (not zip files, but Windows compressed files) on a range of Windows 2003 servers. I have a client pc connected to the target servers and have access on a administrator role basis. My thoughts was to create a Powershell script to handle this problem using WMI or something else? But I'm kind of lost on the possibilities in the WMI world. Any hints/tips are appreciated.
Cheers

I'm not sure if you can do that with WMI, then again I'm no WMI guru. If you can use PowerShell 2.0 this is pretty simple using the new remoting feature e.g.
$computers = 'server1', 'server2', 'server3'
$compressed = Invoke-Command $computers {Get-ChildItem C:\ -r -force -ea 0 |
Where {$_.Attributes -band [IO.FileAttributes]::Compressed}}
Note that each file and dir object stored in $compressed will have an additional property PSComputerName that identifies which computer the deserialized object came from.
Alternatively, if you don't have PowerShell 2.0 you could access the servers via a share e.g.:
$sharePaths = '\\server1\C$', '\\server2\C$', '\\server3\C$'
Get-ChildItem $sharePaths -r -force -ea 0 |
Where {$_.Attributes -band [IO.FileAttributes]::Compressed}
This approach is likely to be slow.

Related

How do you delete user profiles in powershell?

I am writing a powershell script to delete user profiles and I understand the method I am using is not the best. I was wondering what would be a better way to do it? I am still very much new to powershell but I am willing to learn
The code I already have:
$ErrorActionPreference= 'silentlycontinue'
$Users = Get-WmiObject -Class Win32_UserProfile
$IgnoreList = "helpdesk", "administrator", "Default"
:OuterLoop
foreach ($User in $Users) {
foreach ($name in $IgnoreList) {
if ($User.localpath -like "*\$name") {
continue OuterLoop
}
}
$User.Delete()
}
WHy script this when the enterprise approach is GPO.
How to Delete Old User Profiles Using GPO and PowerShell?
No reason to do this from scratch, leverage what others have provided...
Use PowerShell to remove local profiles
How to delete user profiles older than a specified number of days in Windows
...as well as the modules from the MS powershellgallery.com, as you look at whatever approach you decide use.
Find-Module -Name '*user*profile*' | Format-Table -AutoSize
<#
# Results
Version Name Repository Description
------- ---- ---------- -----------
1.0 UserProfile PSGallery This module manages user profiles on local and remote computers
0.1.1 Microsoft.Graph.Users.ProfilePhoto PSGallery Microsoft Graph PowerShell Cmdlets
1.0.6 Get-UserProfile PSGallery The Get-UserProfile module list or remove User Profiles from local
#>
Find-Module -Name '*userprofile*' | Format-List -Force
Update
Yet, you specifically said...
'I understand the method I am using is not the best. I was wondering
what would be a better way to do it?
... and what we all have suggested, using GPO is the best way, the normal industry-accepted enterprise way to do this. Don't script, unless you have no other choice. Windows AD will do this for you.
Don't reinvent the wheel unless you know it's really a better wheel. In learning, of course, there is study, trial, and error, but learn and use from sources that have already done this. There are tons of examples all over the web for this use case. Just search for it. No reason to do this from scratch.
'powershell remove user profiles'
Which are showing what you are already doing... Example(s) - pre-built scripts for this use case via the Ms powershellgallery.com.
Use PowerShell delete a user profile (step-by-step guide)
Get-CimInstance -ComputerName SRV1,SRV2,SRV3 -Class Win32_UserProfile |
Where-Object { $_.LocalPath.split('\')[-1] -eq 'UserA' } |
Remove-CimInstance
Remove-UserProfile - Remove Local User Profiles and Clean C:\Users Directory
This script contains a function (Remove-UserProfile) which is used to
remove user profiles, and additional contents of the C:\Users
directory (if specified) on a local computer.
Download: Remove-UserProfile.ps1
Delete Unused user Profiles on local machine (PowerShell)
Script Delete user profiles over multiple servers v2
ANd using the modules that you see from the above commands, is not something to do later in life. Those are in / available from MS and in PowerShell directly for a reason. Everything you are using in PowerShell is coming from modules hosted on your machine and the ones you download and install from MS and other resources.
Again, use the built-in enterprise tools in Windows or other chosen OS as designed, and if they don't provide what you need, then look to other options, like scripting to an object-level that the enterprise tool is not exposing in its GUI.
I do a similar thing. With a lot of profiles, I've found I've had to wait for the cpu to calm down because of the appxsvc service spawning threads without limit. I used to delete per-user firewall rules, but that doesn't seem necessary anymore.
$excludedprofilelist = 'C:\Users\admin1','C:\users\admin2'
$myprofiles = $profiles | where { !$_.Special -and
$excludedprofilelist -notcontains $_.LocalPath }
$sleepseconds = 1
$numcores = 4
foreach ($profile in $myprofiles) {
$msg = "deleting profile " + $profile.LocalPath
$profile | remove-wmiobject
$msg = $msg + " $?"
echo $msg # the result
# recycle bin
if (test-path c:\`$recycle.bin\$($profile.sid)) {
rm -r c:\`$recycle.bin\$($profile.sid) -force
}
# wait for appx cleanup, what if profile delete error?
#while ( (get-appxpackage -user $profile.sid).count ) {
# sleep 1
#}
do {
# make sure it's running
$id = Get-WmiObject -Class Win32_Service -Filter "Name = 'appxsvc'" |
Select-Object -ExpandProperty ProcessId
# $proc = get-process -id $id
# access is denied
# 4proc.priorityclass = 'belownormal'
$cpu1 = (get-process -Id $id).cpu
sleep $sleepseconds
$cpu2 = (get-process -Id $id).cpu
$cpu = [int](($cpu2 - $cpu1)/($numcores*$sleepseconds) * 100)
} while ($cpu)
}

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.

Why PowerCLI script creates duplicate records using get-vm?

I am trying to build a script that will extract list of VMs from several vsphere servers. At this point it does what I want, but unfortunately it also creates duplicate values in results .csv file.
Just for note serverlist.txt and vicredentials.xml contains the same unique servers.
Import-Module VMware.VimAutomation.Core
Set-PowerCLIConfiguration -DefaultVIServerMode Multiple -Confirm:$false
if (Test-Path 'E:\vSphereScript\vCenterVMList.csv'){Remove-Item 'E:\vSphereScript\vCenterVMList.csv'}
$serverList = Get-Content -Path "E:\vSphereScript\serverlist.txt"
foreach ($server in $serverList) {
$creds = Get-VICredentialStoreItem -file "vSphereScript\vicredentials.xml" -Host $server
Connect-VIServer -server $creds.host -user $creds.user -password $creds.password
Get-VM | Select-Object Name, Guest, VMhost, ResourcePool | Export-Csv -Path "E:\ProgramData\vCenterVMList.csv" -NoTypeInformation -Append
Disconnect-VIServer $server -Confirm:$false
}
Also does anyone have idea why this is so slow?
If I connect to vm directly from powershell and use Get-VM it's almost instantaneous
I don't see anything fundamentally wrong with your code but a couple things do come to mind:
Why are you setting DefaultVIServerMode to Multiple if you're only connecting to a single vCenter at a time?
When you say duplicates, is it the entire VM inventory from a vCenter or is it only particular VMs?
Are the duplicate VMs from a singular vCenter or multiple vCenters?
Are you using any replication based software? (example: SRM)
With regards to speed, Get-VM is fast. However, connecting and disconnecting from vCenter servers are not particularly quick actions.

exporting Powershell Script to CSV

We are getting ready to merge our AD with another. We have about 300 computers that I'm trying to match up with who uses them so the accounts and home folders migrate correctly, and I'm trying to think of the most efficient way to get this information.
We have everyone in an inventory system (Filemaker) (and will be implementing SCCM once we migrate (thank god) ) but we had a few errors when we did our first test batch. Im looking for something I can push out through group policy (possibly?) that will give me the computer name, logged in account, and them email it to me.
So far this is what I have.
[System.Environment]::UserName
[System.Environment]::UserDomainName
[System.Environment]::MachineName
Out-File T:\TEST.txt
But the output is blank. Any idea what I'm doing wrong here? Also is there a way to have this run on multiple computers but write to the same file?
"$env:USERNAME,$env:USERDOMAIN,$env:COMPUTERNAME" | Out-File 'T:\test.txt'
will write the name and domain of the currently logged-in user as well as the hostname of the local computer to the file T:\test.txt.
Using a single file may cause conflicts due to concurrent write attempts, though. It's better to use one file per computer, like this:
"$env:USERDOMAIN\$env:USERNAME" | Out-File "T:\$env:COMPUTERNAME.txt"
Run it as a logon script (or from a logon script), e.g. like this:
powershell -ExecutionPolicy Bypass -File "\\%USERDNSDOMAIN\netlogon\your.ps1"
Get-ADComputer -Filter * -Property * | Select-Object Name | Out-File C:\outdir\machinelist.txt -NoTypeInformation -Encoding UTF8
will get you all machine names, unless you have them already. Either way, use your list of machines in
$MachineList = Get-Content -Path c:\outdir\machinelist.txt;
foreach ($Machine in $MachineList){
($Machine + ": " + #(Get-WmiObject -ComputerName $Machine -Namespace root\cimv2 -Class Win32_ComputerSystem)[0].UserName) | Out-File "C:\outdir\result.txt" -Append
}
If you change the destination directory to somewhere that all computers have access to, it can run on multiple computers. It won't email it to you but you can just grab it.
You'll need to pipe those properties into the file like..
[System.Environment]::UserName, [System.Environment]::UserDomainName, [System.Environment]::MachineName | Out-File T:\Test.txt

On which system is get-acl resolved?

I've inherited a Powershell script that a remote customer uses to recursively search for directories and exports (to csv) multiple ACL values including Path, Owner, FileSystemRights, IdentifyReference, and AccessControlType. The script works great, but I am curious as to how the flow actually takes place. Below is partial script to show code relevant to my question below.
//Partial script begin:
get-childitem $rootdir -recurse | where-object {$_.psIscontainer -eq $true} | foreach-object {
$a = ($_.Fullname)
$b = (get-acl $_.Fullname).Owner
$c = (get-acl $_.Fullname).Access
foreach ($c1 in $c) {
$d = $c1.FileSystemRights
$e = $c1.AccessControlType
//Partial script end.
To my question: If running this script on a remote system, using admin privileges and variable $rootdir = \\someshare, on which system does the get-acl get resolved...on the system hosting the folder structure, or the remote system running the PS script and mapped to the share folder?
Thanks.
// My original question may have been a bit nebulous, so hopefully I can clarify a bit. By using get-acl on a remote system and mapped to a server share folder, will invoking get-acl cause any resource hit on the server during the ACL resolution process...disk I/O, memory, CPU. I am not a programmer, so please bear with me as I try to formulate my question properly.
Assuming that you have all authentication correctly setup (you would run into a double-hop auth problem if i understand your plan correctly) the call to Get-Acl would be executed on the system the script is run on.
From the technet article on the Get-ACL cmdlet
The Get-Acl cmdlet enables you to retrieve the security descriptor
(access control list) for a file, a folder, or even a registry key
It retrieves NTFS persmission for any folder specified, including remote folders.
In your case, it would run from the machine the script is running from, and authenticate to the remote machine using the credentials supplied to retrieve the ACL