powershell workflow and parallel not giving output - powershell

I'm using the following script and it creates the out file correctly, but it's empty. I'm not sure what it's missing exactly. This is my first attempt with using workflows.
workflow DisableIISParallel
{
$ScriptPath = "C:\Scripts\Server_Lists"
$OLD = "Legacy-Servers"
$OldList = Get-Content "$ScriptPath\$OLD.txt"
$objHost=$Records.Length
function DisableIIS ($appName) {
$objHostStr = [System.Net.Dns]::GetHostEntry([string]$objHost).HostName
Invoke-Command -ComputerName $objHostStr { iisreset /stop }
Set-Service -Name W3SVC -StartupType Disabled -Status Stopped -ComputerName $objHostStr
Get-WmiObject -Class win32_service -ComputerName $objHostStr |
where { $_.name -eq "W3SVC" } |
Format-Table -Property #{Expression={$_.PSComputerName};Label="Server";width=18},
#{Expression={$_.Name};Label="Service";width=45},
#{Expression={$_.StartMode};Label="Mode";width=10},
#{Expression={$_.State};Label="State";width=10},
#{Expression={$_.Status};Label="Status";width=10} |
Format-List | out-string -s | ? {$_} | Out-File C:\Scripts\Output\$appName.log -Append
Write-Output "" | Out-File C:\Scripts\Output\$appName.log -Append
}
foreach -parallel($objHost in $OldList)
{
$appName = $OLD
DisableIIS $appName
}
}
DisableIISParallel

This bit is not right:
Get-WmiObject -Class win32_service -ComputerName $objHostStr |
where { $_.name -eq "W3SVC" } |
Format-Table -Property #{Expression={$_.PSComputerName};Label="Server";width=18},
#{Expression={$_.Name};Label="Service";width=45},
#{Expression={$_.StartMode};Label="Mode";width=10},
#{Expression={$_.State};Label="State";width=10},
#{Expression={$_.Status};Label="Status";width=10} |
Format-List | out-string -s | ? {$_} | Out-File C:\Scripts\Output\$appName.log -Append
You should not run the output of one format command (Format-Table) into another format command (Format-List).
Try this (assuming you want tabular format - if not, change the Format-Table to Format-List):
Get-WmiObject -Class win32_service -ComputerName $objHostStr |
where { $_.name -eq "W3SVC" } |
Format-Table #{Expression={$_.PSComputerName};Label="Server";width=18},
#{Expression={$_.Name};Label="Service";width=45},
#{Expression={$_.StartMode};Label="Mode";width=10},
#{Expression={$_.State};Label="State";width=10},
#{Expression={$_.Status};Label="Status";width=10} >> C:\Scripts\Output\$appName.log
And pass in all the variables required to the function e.g.:
function DisableIIS ($appName, $objHost) {
...
}
foreach -parallel($objHost in $OldList)
{
$appName = $OLD
DisableIIS $appName $objHost
}

Related

Append to array in powershell job

I was able to find a piece of code that could ping all systems at once, better than any other job examples I've come across. This thing can take an entire file full of hosts, line by line, and ping them all literally at the same time. But how can I add the ones that are up to my $online array? I tried adding in the true block but it didn't work. Im simply trying to stick $online += $pc somewhere. Any help would be appreciated. Thanks.
$online = #()
$pc = Get-Content C:\servers.txt
$pc | ForEach-Object { Test-Connection -ComputerName $_ -Count 1 -AsJob } | Get-Job | Receive-Job -Wait | Select-Object #{Name='ComputerName';Expression={$_.Address}},#{Name='Reachable';Expression={if ($_.StatusCode -eq 0) { $true } else { $false }}} | ft -AutoSize
You can store the result of your jobs and then filter by Reachable. I've also simplified your code a bit and added -AutoRemove which I consider important to dispose your jobs when done.
$result = Get-Content C:\servers.txt | ForEach-Object {
Test-Connection -ComputerName $_ -Count 1 -AsJob
} | Receive-Job -Wait -AutoRemoveJob | ForEach-Object {
[pscustomobject]#{
ComputerName = $_.Address
Reachable = $_.StatusCode -eq 0
}
}
$online = $result | Where-Object Reachable
# if you want just the `ComputerName` values, you can do
$online = $result | Where-Object Reachable | ForEach-Object ComputerName
# or easier, using member-access enumeration and `.Where` method
$online = $result.Where{ $_.Reachable }.ComputerName
If you're interested in grouping the results between Reachable and Not Reachable during enumeration, the way to do it is with a hash table having 2 List<T> values.
$result = #{
Online = [System.Collections.Generic.List[object]]::new()
Offline = [System.Collections.Generic.List[object]]::new()
}
Get-Content C:\servers.txt | ForEach-Object {
Test-Connection -ComputerName $_ -Count 1 -AsJob
} | Receive-Job -Wait -AutoRemoveJob | ForEach-Object {
$obj = [pscustomobject]#{
ComputerName = $_.Address
Reachable = $_.StatusCode -eq 0
}
if($obj.Reachable) {
return $result['Online'].Add($obj)
}
$result['Offline'].Add($obj)
}
$result.Online.ComputerName # => has all reachable records
I believe the issue here is the pipe ft -autosize.
Try to pipe after the if/else statement as per below:
| ForEach-Object {
if ($_.Reachable -eq $true) {
$online += $_.ComputerName
}
}
Then if you want to view the results you can always do:
$online | ft -AutoSize
I'd also suggest a better formatting as all one line isn't easy to read. Try something like this:
$online = #()
$pc = Get-Content C:\servers.txt
$pc | ForEach-Object {
Test-Connection -ComputerName $_ -Count 1 -AsJob
} | Get-Job | Receive-Job -Wait |
Select-Object #{Name='ComputerName';Expression={$_.Address}},#{Name='Reachable';Expression={
if ($_.StatusCode -eq 0) {
$true
} else {
$false
}
}} | ForEach-Object {
if ($_.Reachable -eq $true) {
$online += $_.ComputerName
}
}
$online | ft -AutoSize

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?

Get ADComputer foreach object and ask for MSSQL-Version

can you please help me?
I am just trying to get a list of all Servers on the Domain and for each server ask simultaneously which mssql server version is running on that server.
Thank you so much!
This is what a already have tried:
Get-ADComputer -Filter {OperatingSystem -Like "*Server*"} -Property \* | foreach object Sqlcmd -Q "SELECT ##VERSION" | foreach object | Format-Table Name,OperatingSystem -Wrap -Auto | Export-CSV AllWindows.csv -NoTypeInformation -Encoding UTF8
I get this error:
The name "object" entered cannot be resolved to a method name.
Try this instead:
$youradmincreds = Get-Credential
Get-ADComputer -Filter {OperatingSystem -Like "*Server*"} -Property * | %{
Invoke-Command -ComputerName $_.SamAccountName -Credential $youradmincreds -ScriptBlock {
$version = Sqlcmd -Q "SELECT ##VERSION"
$version | Format-Table Name,OperatingSystem -Wrap -Auto | Export-CSV AllWindows.csv -NoTypeInformation -Encoding UTF8
}
}
edit: and if you've got ThreadJob module available (which you can also just get wtih find-module ThreadJob | install-module), you can speed the job up
$youradmincreds = Get-Credential
$job = Start-ThreadJob -ScriptBlock {
Invoke-Command -ComputerName $input -Credential $youradmincreds -ScriptBlock {
$version = Sqlcmd -Q "SELECT ##VERSION"
$version | Format-Table Name,OperatingSystem -Wrap -Auto | Export-CSV AllWindows.csv -NoTypeInformation -Encoding UTF8
}
} -InputObject (Get-ADComputer -Filter {OperatingSystem -Like "*Server*"} | select -ExpandProperty SamAccountName)
$job | Wait-Job | Receive-Job

How to check if hotfix KBxxxxxx (example: KB4012212) is installed in the PC or not?

I will create (with PowerShell script) a table and add the result(Positive/negative) to it.
I have a text file computers.txt, in which all PCs are listed.
Like this
CSNAME Hotfixinfo
PC1 is installed
PC2 is not installed
PC3 is installed
etc.
With my actual script I can only see the positive result.
Get-Content .\computers.txt | Where {
$_ -and (Test-Connection $_ -Quiet)
} | foreach {
Get-Hotfix -Id KB4012212 -ComputerName $_ |
Select CSName,HotFixID |
ConvertTo-Csv |
Out-File "C:\$_.csv"
}
I'd suggest parsing through and handling the positive and negative results (also faster than the pipeline ForEach-Object):
:parse ForEach ($Computer in (Get-Content C:\Path\computers.txt))
{
If (Test-Connection $Computer -Quiet)
{
$Result = Get-Hotfix -Id KB4012212 -ComputerName $Computer -ErrorAction 'SilentlyContinue'
If ($Result)
{
$Result |
Select-Object -Property CSName,HotFixID |
ConvertTo-Csv -NoTypeInformation |
Out-File "C:\$Computer.csv"
Continue :parse
}
"`"CSName`",`"HotFixID`"`r`n`"$Computer`",`"NUL`"" |
Out-File "C:\$Computer.csv"
} Else { Write-Host 'Unable to connect to $Computer' }
}

How to edit my script to combine its outputs in one table per server from serverlist?

Could you please inform me how can I make my script to format its output in a single table for all "services" per "server"?
Please find my current PowerShell script below:
$serverList = gc computer.txt
$serviceList = gc service.txt
if ((Test-Path OUTPUT.txt) -eq $true) {
Write-Host "Deleting existing OUTPUT file"
Remove-Item OUTPUT.txt
}
ForEach ($server in $serverList)
{
$style = #{Expression={$server};Label="Server Name";width=30}, `
#{Expression={$_.Name};Label="Service Name";width=20}, `
#{Expression={$_.StartMode};Label="StartMode";width=10}, `
#{Expression={$_.State};Label="State";width=10}, `
#{Expression={$_.ProcessId};Label="ProcessId";width=10}
Write-Host "Starting Service Check on $server"
ForEach ($service in $serviceList)
{
Get-WmiObject -Class Win32_Service -ComputerName $server -Filter "Name='$service'" | Select-Object -Property Name, StartMode, State, ProcessId | Format-Table $style | Out-File OUTPUT.txt -Append
}
Write-Host "Service Check Completed on $server"
}
WMI appends the property PSComputername. You can just append it in your select-object-command like so:
Get-WmiObject -Class Win32_Service -ComputerName $server -Filter "Name='$service'" | Select-Object -Property PScomputername, Name, StartMode, State, ProcessId | Format-Table $style | Out-File OUTPUT.txt -Append