Start-Job output in CSV format - powershell

How to get the jobs output in an CSV format. When I execute the command below, I get the output on the screen, but when I export it to CSV it does not have the same format.
$wmidiskblock = {
Get-WmiObject -ComputerName $args[0] -Class Win32_LogicalDisk -Filter "DeviceID='C:'" |
Select-Object Size, Freespace
(Test-Connection -ComputerName $args[0] | Select-Object -ExpandProperty IPV4Address) |
Select-Object IPAddressToString -Unique
Get-Service -ComputerName $args[0] | ? {
($_.DisplayName -match "VMWARE") -and
($_.Name -notmatch "mbcs") -and
($_.Name -notmatch "vmvss") -and
($_.Name -notmatch "vmware-autodeploy-waiter") -and
($_.Name -notmatch "vmware-network-coredump") -and
($_.Name -notmatch "VMWareNetworkCoredumpWebserve") -and
($_.Name -notmatch "vsan-health")
} -ErrorAction Stop
}
$com = #()
$com = "Server-x" , "Server-y"
$pop = #()
foreach ($ser in $com) {
[array]$pop += Start-Job -ArgumentList $ser -ScriptBlock $wmidiskblock -Name top1
}
Get-Job -Name top1 | Receive-Job -Keep
Actual output:
Size : 64422408192
Freespace : 4908081152
RunspaceId : cdb3xxxxx-xxxx-xxxx-xxxx-xxxxxxxxx
IPAddressToString : x.x.x.x
RunspaceId : cdb3xxxxx-xxxx-xxxx-xxxx-xxxxxxxxx
Status : Running
Name : client_service
DisplayName : VMware Horizon Client
Status : Running
Name : ftnlsv3hv
DisplayName : VMware Netlink Supervisor Service
Status : Running
Name : ftscanmgrhv
DisplayName : VMware Scanner Redirection Client
Server-x
Desired output (as a CSV file):
Server Totalspace in GB Freespace in GB IP VMware ESX Agent Manager VMware Inventory Service
Server-x 100 36 144.215.150.67 Running Running

You need to transform your data to something that's actually exportable to CSV. Basically that means you need to take the bits of information you extract from the servers and put it into one object for each server:
$wmidiskblock = {
$disk = Get-WmiObject ...
$addr = (Test-Connection ...
$svc = Get-Service ...
$prop = [ordered]#{
Server = $args[0]
Totalspace = $disk.Size
Freespace = $disk.Freespace
IP = $addr
}
$svc | ForEach-Object { $prop[$_.Name] = $_.Status }
New-Object -Type PSObject -Property $prop
}
Then you can export the data received from the jobs like this:
... | Receive-Job | Export-Csv 'C:\path\to\output.csv' -NoType -Append

Related

PowerShell not running all lines in Function

Below Function is not running the lines "If ($script:AADServersTable)" down... I have put a write-host and that is working, however the variables are not working below that
Function get-AADVariables
{
$script:AADServersTable = New-Object 'System.Collections.Generic.List[System.Object]'
$scriptBlockaadinstalled = {
Get-WmiObject -Class Win32_Product |
where name -eq "Microsoft Azure AD Connect synchronization services" | select Name, Version}
##$scriptBlockaadinstalled = {hostname}
Import-Module ActiveDirectory
$servers = Get-ADComputer -Filter 'operatingsystem -like "*server*" -and enabled -eq "true"' | Select-Object -Property Name -ExcludeProperty Release
## just a single invoke-command
foreach ($server in $servers) {
$aadinstalledresults = Invoke-Command -ComputerName $server.name -ScriptBlock $scriptBlockaadinstalled ##-HideComputerName
$aadinstalledresults = $aadinstalledresults.PSComputerName
$script:AADServersTable.Add($aadinstalledresults)
}
If ($script:AADServersTable) {
Write-Host 'working'
$AADServers = ($script:AADServersTable | Group-Object -NoElement).Name | Get-Unique
$AADServers = $AADServers -split "`n"
$AADServer = $AADServers[0]
$StandByAADServer = $AADServers[1]
$SecondStandByAADServer = $AADServers[2]
}
}

Script to remove user profiles using powershell

I'm trying to build a powershell script that I can use to delete all or some of the user profiles on multiple pc's since they often cause the drives to go full.
I found the current script which I got to work for me, but I'd like to optimize it so I can input or import a list of computers where I want him to remove all the user profiles from.
Can you guys help me to input this feature?
Current Code:
$ExcludedUsers ="admin","test"
$RunOnServers = $false
[int]$MaximumProfileAge = 0 # Profiles older than this will be deleted
$osInfo = Get-CimInstance -ClassName Win32_OperatingSystem
if ($RunOnServers -eq $true -or $osInfo.ProductType -eq 1) {
New-EventLog -LogName Application -Source "Stone Profile Cleanup" -ErrorAction SilentlyContinue
$obj = Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special -and $_.Loaded -eq $false )}
#$output = #()
foreach ($littleobj in $obj) {
if (!($ExcludedUsers -like $littleobj.LocalPath.Replace("C:\Users\",""))) {
$lastwritetime = (Get-ChildItem -Path "$($littleobj.localpath)\AppData\Local\Microsoft\Windows\UsrClass.dat" -Force ).LastWriteTime
if ($lastwritetime -lt (Get-Date).AddDays(-$MaximumProfileAge)) {
$littleobj | Remove-WmiObject
# $output += [PSCustomObject]#{
# 'RemovedSID' = $littleobj.SID
# 'LastUseTime' = $litteobj.LastUseTime
# 'LastWriteTime' = $lastwritetime
# 'LocalPath' = $littleobj.LocalPath
# }
}
}
}
#$output | Sort LocalPath | ft
#$output | Sort LocalPath | ft * -AutoSize | Out-String -Width 4096 | Out-File -filepath "C:\MyOutput.TXT" -append -Encoding Unicode
Write-EventLog –LogName Application –Source "Stone Profile Cleanup" –EntryType Information –EventID 1701 -Category 2 -Message ("Profiles older than $MaximumProfileAge days have been cleaned up")
}$ExcludedUsers ="adminbholemans","testbholemans1"
$RunOnServers = $false
[int]$MaximumProfileAge = 0 # Profiles older than this will be deleted
$osInfo = Get-CimInstance -ClassName Win32_OperatingSystem
if ($RunOnServers -eq $true -or $osInfo.ProductType -eq 1) {
New-EventLog -LogName Application -Source "Stone Profile Cleanup" -ErrorAction SilentlyContinue
$obj = Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special -and $_.Loaded -eq $false )}
#$output = #()
foreach ($littleobj in $obj) {
if (!($ExcludedUsers -like $littleobj.LocalPath.Replace("C:\Users\",""))) {
$lastwritetime = (Get-ChildItem -Path "$($littleobj.localpath)\AppData\Local\Microsoft\Windows\UsrClass.dat" -Force ).LastWriteTime
if ($lastwritetime -lt (Get-Date).AddDays(-$MaximumProfileAge)) {
$littleobj | Remove-WmiObject
# $output += [PSCustomObject]#{
# 'RemovedSID' = $littleobj.SID
# 'LastUseTime' = $litteobj.LastUseTime
# 'LastWriteTime' = $lastwritetime
# 'LocalPath' = $littleobj.LocalPath
# }
}
}
}
#$output | Sort LocalPath | ft
#$output | Sort LocalPath | ft * -AutoSize | Out-String -Width 4096 | Out-File -filepath "C:\MyOutput.TXT" -append -Encoding Unicode
Write-EventLog –LogName Application –Source "Stone Profile Cleanup" –EntryType Information –EventID 1701 -Category 2 -Message ("Profiles older than $MaximumProfileAge days have been cleaned up")
}
I found this piece of code for the computer input but I'm not sure how I can implement it properly.
Get-CimInstance -ComputerName SRV1,SRV2,SRV3 -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('\')[-1] -eq 'UserA' } | Remove-CimInstance
Thanks for the help everyone.
Get-CimInstance -ComputerName SRV1,SRV2,SRV3 -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('')[-1] -eq 'UserA' } | Remove-CimInstance
Do u test it before? Work OK?

Correlate Physical Device ID to Volume Device ID

I'm trying to utilize WMI via PowerShell to run through SAN storage on remote servers to grab the Windows disk management volume label.
The only way I've found to do this is to correlate the volume device id (\\?\Volume{34243...} with the physical disk device ID (\\.\PHYSICALDRIVE01).
However, I haven't been able to find out how to link those two fields together. Is this possible with WMI?
For volumes that were assigned a drive letter you can correlate disks and volumes like this:
Get-WmiObject Win32_DiskDrive | ForEach-Object {
$disk = $_
$partitions = "ASSOCIATORS OF " +
"{Win32_DiskDrive.DeviceID='$($disk.DeviceID)'} " +
"WHERE AssocClass = Win32_DiskDriveToDiskPartition"
Get-WmiObject -Query $partitions | ForEach-Object {
$partition = $_
$drives = "ASSOCIATORS OF " +
"{Win32_DiskPartition.DeviceID='$($partition.DeviceID)'} " +
"WHERE AssocClass = Win32_LogicalDiskToPartition"
Get-WmiObject -Query $drives | ForEach-Object {
$driveLetter = $_.DeviceID
$fltr = "DriveLetter='$driveLetter'"
New-Object -Type PSCustomObject -Property #{
Disk = $disk.DeviceID
DriveLetter = $driveLetter
VolumeName = $_.VolumeName
VolumeID = Get-WmiObject -Class Win32_Volume -Filter $fltr |
Select-Object -Expand DeviceID
}
}
}
}
Otherwise it doesn't seem possible with WMI.
On Windows 8/Server 2012 or newer you could use the Get-Partition cmdlet, though:
Get-Partition | Select-Object DiskNumber, DriveLetter, #{n='VolumeID';e={
$_.AccessPaths | Where-Object { $_ -like '\\?\volume*' }
}}
I have done a script that collects the most important stuff from volume and disk WMI. its used with getting information from a Remote Desktop server where a lot of disks are mounted but can be hard to find who is using which disk. its using AD to query the user and connect it with the SID to find the file path. so its a matter of first collecting all the data from the different disk commands and then combine the outputs. the most important command to bind disk data with volume data is the get-partition that shows deviceid
Function Get-VHDMount {
[cmdletbinding()]
Param(
[Parameter(Position=0,ValueFromPipeline=$True)]
[ValidateNotNullorEmpty()]
[OBJECT[]]$Computername,
[STRING]$RDSPATH = '\\rdsprofiles'
)
foreach ($computer in $Computername) {
$RDSItems = (Get-ChildItem $RDSPATH -Recurse -Filter *.vhdx)
$VolumeInfo = invoke-command -ComputerName $computer -scriptblock {Get-Volume | select *}
$VHDMountInfo = Get-WmiObject Win32_Volume -ComputerName $computer |where Label -eq 'user Disk'
$partitioninfo = invoke-command -ComputerName $computer -scriptblock {Get-Partition | Select-Object DiskNumber, #{n='VolumeID';e={$_.AccessPaths | Where-Object { $_ -like '\\?\volume*' }}}}
foreach ($VHDmount in $VHDMountInfo) {
$adinfo = Get-ADUser ($VHDmount.name | Split-Path -Leaf)
[PSCUSTOMOBJECT]#{
Computername = $computer
username = $VHDmount.name | Split-Path -Leaf
displayname = $adinfo.name
SID = $adinfo.SID
deviceid = $VHDmount.deviceid
capacity = ([MATH]::ROUND(($VHDmount.capacity) / 1gb))
HealthStatus = ($VolumeInfo | where ObjectId -eq ($VHDmount.deviceid)).HealthStatus
DiskNumber = ($partitioninfo | where Volumeid -eq ($VHDmount.deviceid)).DiskNumber
Path = ($RDSItems | where fullname -like "*$($adinfo.SID)*").FullName
}
}
}
}

Powershell Match virtual hard disks in Virtual Center with their disk labels

I would like to match the drive in the windows os to the vCenter *.vmdk.
Here is a link for the informations I need. I find no way to get "Location 192 (Bus Number 0, Target Id 0, LUN 0)" with powershell (info from disk). From the WMI I don't get this information...
Can someone help?
The modified script:
$Vm = "VMName"
if (($VmView = Get-View -ViewType VirtualMachine -Filter #{"Name" = $Vm})) {
$Out = Get-WmiObject -Class win32_diskdrive -Property Index, SCSIPort, SCSITargetId -ComputerName $Vm
#Invoke-VMScript "wmic path win32_diskdrive get Index, SCSIPort, SCSITargetId /format:csv" -vm $VM -scripttype "bat"
foreach ($VirtualSCSIController in ($VMView.Config.Hardware.Device | where {$_.DeviceInfo.Label -match "SCSI-Controller"})) {
foreach ($VirtualDiskDevice in ($VMView.Config.Hardware.Device | where {$_.ControllerKey -eq $VirtualSCSIController.Key})) {
$VirtualDisk = "" | Select SCSIController, DiskName, SCSI_Id, DiskFile, DiskSize, WindowsDisk
$VirtualDisk.SCSIController = $VirtualSCSIController.DeviceInfo.Label
$VirtualDisk.DiskName = $VirtualDiskDevice.DeviceInfo.Label
$VirtualDisk.SCSI_Id = "$($VirtualSCSIController.BusNumber) : $($VirtualDiskDevice.UnitNumber)"
$VirtualDisk.DiskFile = $VirtualDiskDevice.Backing.FileName
$VirtualDisk.DiskSize = $VirtualDiskDevice.CapacityInKB * 1KB / 1GB
# Match disks based on SCSI ID
$DiskMatch = $Out | ?{($_.SCSIPort - 2) -eq $VirtualSCSIController.BusNumber -and $_.SCSITargetID -eq $VirtualDiskDevice.UnitNumber}
if ($DiskMatch){
$VirtualDisk.WindowsDisk = "Disk $($DiskMatch.Index)"
}
else {Write-Host "No matching Windows disk found for SCSI id $($VirtualDisk.SCSI_Id)"}
$DiskInfo += $VirtualDisk
}
}
$DiskInfo | Out-GridView
I had to change $DiskMatch = $Out | ?{($_.SCSIPort - 2) -eq <-- Replace - 1 with - 2.
And put an "-" between SCSI Controller by {$_.DeviceInfo.Label -match "SCSI-Controller"})).
Why do I have to subtract 2 from the SCSIPort?
The following script will match the local windows disk with the vmWare disk.
Date : 2017.10.27 21:28:01
vCenterName : vCenterName
vmName : SERVER
vmWareSCSIController : SCSI controller 0
wmWareSCSIID : 0 : 0
vmWareDiskName : Hard disk 1
vmWareDiskFile : [Datastore] vm.vmdk
vmWareSizeGB : 40
WindowsSerialNumber : WindowsSerialNumber
WindowsSCSIBus : 0
WindowsSCSILogicalUnit : 0
WindowsSCSIPort : 2
WindowsSCSITargetId : 0
WindowsDisk : \\SERVER\root\cimv2:Win32_DiskDrive.DeviceID="\\\\.\\PHYSICALDRIVE0"
WindowsDriveLetter : C:
WindowsLocicalDiskSizeGB : 39.9980430603027
WindowsLocicalDiskFreeSpaceGB : 9.30975723266602
WindowsLocicalDiskUsedSpaceGB : 30.6882858276367
#Variables
$Vm = Get-VM -Name 'VMName'
$ComputerName = 'ComputerName'
$obj_DiskDrive = #()
$obj_LogicalDisk = #()
$obj_LogicalDiskToPartition = #()
$obj_DiskDriveToDiskPartition = #()
$obj_VMView = #()
$obj_DiskInfos = #()
#Get wmi objects
$obj_DiskDrive = Get-WmiObject -Class win32_DiskDrive -ComputerName $ComputerName
$obj_LogicalDisk = Get-WmiObject -Class Win32_LogicalDisk -ComputerName $ComputerName
$obj_LogicalDiskToPartition = Get-WmiObject -Class Win32_LogicalDiskToPartition -ComputerName $ComputerName
$obj_DiskDriveToDiskPartition = Get-WmiObject -Class Win32_DiskDriveToDiskPartition -ComputerName $ComputerName
#Get vm
$obj_VMView = Get-View -ViewType VirtualMachine -Filter #{"Name" = "$($Vm.Name)"}
#Get vm disk
$obj_VMDisk = Get-HardDisk -VM $Vm
#Match the informations
foreach ($obj_vmWareSCSIController in ($obj_VMView.Config.Hardware.Device | Where-Object -FilterScript {$_.DeviceInfo.Label -match "SCSI"}))
{
foreach ($obj_vmWareDiskDevice in ($obj_VMView.Config.Hardware.Device | Where-Object -FilterScript {$_.ControllerKey -eq $obj_vmWareSCSIController.Key}))
{
$obj_tempDiskInfos = "" | Select-Object -Property Date, vCenterName, vmName, vmWareSCSIController, wmWareSCSIID, vmWareDiskName, vmWareDiskFile,
vmWareSizeGB, WindowsSerialNumber, WindowsSCSIBus, WindowsSCSILogicalUnit, WindowsSCSIPort, WindowsSCSITargetId, WindowsDisk, WindowsDriveLetter,
WindowsLocicalDiskSizeGB, WindowsLocicalDiskFreeSpaceGB, WindowsLocicalDiskUsedSpaceGB
#Select WMI object
$obj_currentDiskDrive = #()
$obj_currentDiskDrive = $obj_DiskDrive | Where-Object -FilterScript {$_.SerialNumber -eq $obj_vmWareDiskDevice.Backing.Uuid.Replace("-","")}
$obj_currentDiskDriveToDiskPartition = #()
$obj_currentDiskDriveToDiskPartition = $obj_DiskDriveToDiskPartition | Where-Object -FilterScript {$_.Antecedent -eq $obj_currentDiskDrive.Path}
$obj_currentLogicalDiskToPartition = #()
$obj_currentLogicalDiskToPartition = $obj_LogicalDiskToPartition | Where-Object -FilterScript {$_.Antecedent -eq $obj_currentDiskDriveToDiskPartition.Dependent}
$obj_currentLogicalDisk = #()
$obj_currentLogicalDisk = $obj_LogicalDisk | Where-Object -FilterScript {$_.Path.Path -eq $obj_currentLogicalDiskToPartition.Dependent}
#Select vmWare object
$obj_CurrentvmWareHarddisk = #()
$obj_CurrentvmWareHarddisk = $obj_VMDisk | Where-Object -FilterScript {$_.Name -eq $obj_vmWareDiskDevice.DeviceInfo.Label}
#Generate output
$obj_tempDiskInfos.Date = Get-Date -Format "yyyy.MM.dd HH:mm:ss"
$obj_tempDiskInfos.vCenterName = $defaultVIServer.Name
$obj_tempDiskInfos.vmName = $Vm.Name
$obj_tempDiskInfos.vmWareSCSIController = $obj_vmWareSCSIController.DeviceInfo.Label
$obj_tempDiskInfos.wmWareSCSIID = "$($obj_vmWareSCSIController.BusNumber) : $($obj_vmWareDiskDevice.UnitNumber)"
$obj_tempDiskInfos.vmWareDiskName = $obj_vmWareDiskDevice.DeviceInfo.Label
$obj_tempDiskInfos.vmWareDiskFile = $obj_vmWareDiskDevice.Backing.FileName
$obj_tempDiskInfos.vmWareSizeGB = $obj_CurrentvmWareHarddisk.CapacityGB
$obj_tempDiskInfos.WindowsSerialNumber = $obj_currentDiskDrive.SerialNumber
$obj_tempDiskInfos.WindowsSCSIBus = $obj_currentDiskDrive.SCSIBus
$obj_tempDiskInfos.WindowsSCSILogicalUnit = $obj_currentDiskDrive.SCSILogicalUnit
$obj_tempDiskInfos.WindowsSCSIPort = $obj_currentDiskDrive.SCSIPort
$obj_tempDiskInfos.WindowsSCSITargetId = $obj_currentDiskDrive.SCSITargetId
$obj_tempDiskInfos.WindowsDisk = $obj_currentDiskDrive.Path.Path
$obj_tempDiskInfos.WindowsDriveLetter = ($obj_currentLogicalDisk).Caption
$obj_tempDiskInfos.WindowsLocicalDiskSizeGB = $obj_currentLogicalDisk.Size / 1GB
$obj_tempDiskInfos.WindowsLocicalDiskFreeSpaceGB = $obj_currentLogicalDisk.FreeSpace / 1GB
$obj_tempDiskInfos.WindowsLocicalDiskUsedSpaceGB = ($obj_currentLogicalDisk.Size / 1GB) - ($obj_currentLogicalDisk.FreeSpace / 1GB)
$obj_DiskInfos += $obj_tempDiskInfos
}
}
$obj_DiskInfos

How to list all the services running with a service account in a server using Powershell

I want to update the password of all the services running under one account on multiple servers using powershell. i tried Get-process, Get-WMIObject cmdlets, but these two commands don't have serviceaccount usage. is there a way to update password of all the services running with an account by passing service account,password as parameters to the script.
To get list of services using a particular account you can do:
Get-WmiObject "win32_service" -Filter "StartName='domain\\user'"
To change the password for these, you can do:
Get-WmiObject "win32_service" -Filter "StartName='domain\\user'" |
%{$_.StopService();$_.Change($null,$null,$null,$null,$null,$null,$null,"blah");}
From here: http://www.send4help.net/change-remote-windows-service-credentials-password-powershel-495
try this:
Function GLOBAL:GET-PROCESSUSER ( $ProcessID ) {
(GET-WMIOBJECT win32_process –filter “Handle=$ProcessID”).GetOwner().User
}
$svcs = Get-Process | Select-Object name, starttime, ID
$a = #()
foreach ($svc in $svcs)
{
if ( $svc.name -ne "Idle" -and $svc.name -ne "System")
{
$al = New-Object System.Object
$al | Add-Member -type NoteProperty -name Name -Value $svc.name
$al | Add-Member -type NoteProperty -name Owner -Value ( get-processuser $svc.id)
$a += $al
}
}
$a
Edit after comment:
$a = (GET-WMIOBJECT win32_service) | ? { $_.startname -eq "domain\\username"} | %{$_.StopService();$_.Change($null,$null,$null,$null,$null,$null,$null,"newpassword");}
This is what you guys need
Get-WMIObject Win32_Service | Where-Object {$_.startname -ne "localSystem" }| Where-Object {$_.startname -ne "NT AUTHORITY\LocalService" } |Where-Object {$_.startname -ne "NT AUTHORITY\NetworkService" } |select startname, name
Yeah - this seems to be the best approach
Get-WMIObject Win32_Service | Where-Object {($_.startname -ne "NT AUTHORITY\LocalService") -and ($_.startname -ne "NT AUTHORITY\NetworkService") -and ($_.startname -ne "localSystem") } `
|select #{ Name = "Service Account " ; Expression = { ( $_.startname ) } }, `
#{ Name = "Service Dispaly Name " ; Expression = { ( $_.name ) } }, StartMode,State, Status | FT -AutoSize