Select-Object -Property parameter prevents getting object while in loop - powershell-5.0

Please help me understand why I cannot output the object with Select-Object using -Property parameter while being in loop.
Here is example:
$GPjob = Start-Job -ScriptBlock {Get-Process | Select-Object -First 1}
for ($i = 0 ; $i -lt 200000 ; $i++) {
if (($GPjob.State -eq 'Completed') -and ($GPjob.HasMoreData)) {
"Step 1: $(Get-Date) : `$i=$i"
Receive-Job $GPjob | Select-Object -Property Name
"Step 2: $(Get-Date) : `$i=$i"
}
}
Step 1, Receive-Job and Step 2 lines should be executed one by one inside one of the $i cycles. So I should see all three outputs at once. But actually, I don't see output from Receive-Job and Step 2 until entire loop is over.
But if I don't use -Property parameter for Receive-Job, everything goes as expected: I see all three outputs at once.

This way comes out faster, but I can't explain why. Maybe it's how Out-Default works. I got the same results with &{ for () } and foreach-object. In the ise debugger, if I put a breakpoint on the receive-job line, the output comes out right after I step past the "Step 2" line.
Receive-Job $GPjob | Select-Object -ExpandProperty Name

I still didn't find the answer, but I found a workaround.
Format-Table fixes this mistery. So the next code works just as expected:
$GPjob = Start-Job -ScriptBlock {Get-Process | Select-Object -First 1}
for ($i = 0 ; $i -lt 200000 ; $i++) {
if (($GPjob.State -eq 'Completed') -and ($GPjob.HasMoreData)) {
"Step 1: $(Get-Date) : `$i=$i"
Receive-Job $GPjob | Select-Object -Property Name | ft
"Step 2: $(Get-Date) : `$i=$i"
}
}

Related

Devices locking an account after password reset

Trying to find what devices a user is logged on to because her account keeps locking.
This is my script but it gives me the dreaded Get-User.Name is not recognized as a cmdlet, etc...Relatively new to powershell. User names are first. Last and Domain is OCSD Any ideas?
$Computers = OCSD -Filter {(enabled -eq "true") -and (OperatingSystem -Like "*XP*")} | Select-Object -ExpandProperty Name
$output=#()
ForEach($PSItem in $Computers) {
$Celeste.Mott = .\Get-$User.name Win32_ComputerSystem -ComputerName $PSItem | Select-Object -ExpandProperty UserName
$Obj = New-Object -TypeName PSObject -Property # {
"Computer" = $PSItem
"User" = $User.name
}
$output += $Obj
}
$output

PowerShell 7. ForEach-Object -Parallel Does Not Autheticate Against Azure PowerShell

We wrote a script that supposed to execute Azure PowerShell commands in parallel. The problem is when we increase -ThrottleLimit higher than one, some of the commands are not being performed properly. The script is:
# Writing IPs for whitelisting into file.
Add-Content -Path IPs.txt -Value ((Get-AzWebApp -ResourceGroupName "ResourceGroup1" -Name "WebApp1").OutboundIpAddresses).Split(",")
Add-Content -Path IPs.txt -Value ((Get-AzWebApp -ResourceGroupName "ResourceGroup1" -Name "WebApp1").PossibleOutboundIpAddresses).Split(",")
# Writing new file with inique IPs.
Get-Content IPs.txt | Sort-Object -Unique | Set-Content UniqueIPs.txt
# Referencing the file.
$IPsForWhitelisting = Get-Content UniqueIPs.txt
# Assigning priotiry number to each IP
$Count = 100
$List = foreach ($IP in $IPsForWhitelisting) {
$IP|Select #{l='IP';e={$_}},#{l='Count';e={$Count}}
$Count++
}
# Whitelisting all the IPs from the list.
$List | ForEach-Object -Parallel {
$IP = $_.IP
$Priority = $_.Count
$azureApplicationId ="***"
$azureTenantId= "***"
$azureApplicationSecret = "***"
$azureSecurePassword = ConvertTo-SecureString $azureApplicationSecret -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($azureApplicationId , $azureSecurePassword)
Connect-AzAccount -Credential $credential -TenantId $azureTenantId -ServicePrincipal | Out-null
echo "IP-$Priority"
echo "$IP/24"
echo $Priority
Add-AzWebAppAccessRestrictionRule -ResourceGroupName "ResourceGroup1" -WebAppName "WebApp1" -Name "IP-$Priority" -Priority $Priority -Action Allow -IpAddress "$IP/24"
} -ThrottleLimit 1
If ThrottleLimit is set to 1 - 8 rules are being created, if ThrottleLimit is set to 2 - 7 rules are being created, 3 - 4 rules, 10 - 1 rule, hence some rules are being skipped.
What is the reason for such behavior?
In short - the -Parallel parameter does not (yet perhaps) magically import all dependent variables that fall in the scope of the For-EachObject block. In reality PWSH spans separate processes and only the array that is looped over will be implicitly passed, all other variables need explicit designations.
One should use the $using: directive (prefix) to denote which variables are to be imported (made visible) in the parallel code block.
Example:
$avar = [Int]10
$bvar = [Int]20
$list = #('here', 'it', 'eees')
$list | ForEach-Object -Parallel {
Write-Output "(a, b) is here ($($using:avar), $($using:bvar))"
Write-Output "(a, b) missing ($($avar), $($bvar))"
Write-Output "Current element is $_"
}```
*thus - the described behavior is likely due to the fact that config. variables are not imported (at all) and thus the operations silently fail.*

Powershell script to run list of sql files

I want to read a file that contains a line separated list of *.sql file names (all located at the same directory) to execute the following:
$reader = [System.IO.File]::OpenText("_Scripts.txt")
try {
for(;;) {
$line = $reader.ReadLine()
if ($line -eq $null) { break }
#output
$out = $line.split(".")[0] + ".txt" ;
# -serverinstance u should change the value of it according to use
invoke-sqlcmd -inputfile $line -serverinstance "." | format-table | out-file -filePath $out
$line
}
}
finally {
$reader.Close()
}
I'm trying to execute this script file by using a batch file containing the command:
powershell.exe -ExecutionPolicy Bypass -Command "_scripts.ps1"
but I get the error shown below:
Can anyone help me fix my ps1 script please?
This works for me:
$lines = Get-Content C:\Temp\TEST\_Scripts.txt
ForEach ($line in $lines)
{
$out = $line.split(".")[0] + ".txt" ;
Invoke-Sqlcmd -InputFile $line -ServerInstance "localhost" -Database "master" | Format-Table | Out-File -FilePath $out
}

How to add hardcoded value to WMI output in Powershell

I am new to powershell, i am trying to retrieve the SQL Services details using WMI object. My code is as follows:
$InputFile = Import-Csv "C:\input\Servers.csv" | %{ $_.Instance = $_.Instance -replace "\\.*?$" ; $_}
Write-Output "SQL Services details for Server:" | Out-File C:\output\SQLCHECK.STOPPED.LOG
Write-Output "********************************" | Out-File C:\output\SQLCHECK.STOPPED.LOG -Append
foreach($Servers in $Inputfile)
{
Write-Output $Servers|ft -AutoSize | Out-File C:\output\SQLCHECK.STOPPED.LOG
$Servicesstate=Get-WmiObject win32_service -ComputerName $Servers.instance | Select Name, Startmode, State | Where-Object `
{$_.name -like "*SQL*" -and $_.Startmode -match "Auto" -and $_.state -match "Stopped"} | ft -auto
if (!$Servicesstate )
{
Write-Host "No Services in STOP state"
Write-Output "No Services in STOPPED state" | Out-File C:\output\SQLCHECK.STOPPED.LOG -Append
}
Else
{
echo ($Servicesstate )
Write-Output ($Servicesstate) | Out-File C:\output\SQLCHECK.STOPPED.LOG -Append
}
}
My Output will come something like this:
Instance Name:
ABCDEFGH
Name Startmode State
SQLdmCollectionService$Default Auto Stopped
SQLdmManagementService$Default Auto Stopped
SQLdmPredictiveAnalyticsService$Default Auto Stopped
My question is, how to add a additional column to the output and add custom text as values.
I want to add remarks column and display failed if any services are stopped.
Name Startmode State Remarks
SQLdmCollectionService$Default Auto Stopped Failed
SQLdmManagementService$Default Auto Stopped Failed
SQLdmPredictiveAnalyticsService$Default Auto Stopped Failed
Your columns are defined by what you put in Select-Object, as you only have Name, Startmode and State those will be the columns.
Change
Select Name,Startmode,State
To
Select-Object Name,Startmode,State,Remark
By adding another property called Remarks you will effectively add another column to your output and you can change the value of Remark by calling the property like so
$Servicestate.Remark = 'Failed'
So you're final code might look something like this
$InputFile = Import-Csv "C:\input\Servers.csv" | %{ $_.Instance = $_.Instance -replace "\\.*?$" ; $_}
Write-Output "SQL Services details for Server:" | Out-File C:\output\SQLCHECK.STOPPED.LOG
Write-Output "********************************" | Out-File C:\output\SQLCHECK.STOPPED.LOG -Append
foreach($Servers in $Inputfile)
{
Write-Output $Servers|ft -AutoSize | Out-File C:\output\SQLCHECK.STOPPED.LOG
$Servicesstate=Get-WmiObject win32_service -ComputerName $Servers.instance | Select Name, Startmode, State | Where-Object `
{$_.name -like "*SQL*" -and $_.Startmode -match "Auto" -and $_.state -match "Stopped"} | ft -auto
if (!$Servicesstate )
{
# Edit the new column before you output
$Servicestate.Remark = 'Failed'
Write-Host "No Services in STOP state"
Write-Output "No Services in STOPPED state" | Out-File C:\output\SQLCHECK.STOPPED.LOG -Append
}
Else
{
# Edit the new column before you output
$Servicestate.Remark = 'Success'
echo ($Servicesstate )
Write-Output ($Servicesstate) | Out-File C:\output\SQLCHECK.STOPPED.LOG -Append
}
}
When assigning your values to $servicestate you can pipe to a Select command and create an extra value with a hashtable. Check out this slightly modified version of your script, paying close attention to line 9:
$InputFile = Import-Csv "C:\input\Servers.csv" | %{ $_.Instance = $_.Instance -replace "\\.*?$" ; $_}
Write-Output "SQL Services details for Server:" | Out-File C:\output\SQLCHECK.STOPPED.LOG
Write-Output "********************************" | Out-File C:\output\SQLCHECK.STOPPED.LOG -Append
foreach($Servers in $Inputfile)
{
Write-Output $Servers|ft -AutoSize | Out-File C:\output\SQLCHECK.STOPPED.LOG
$Servicesstate=Get-WmiObject win32_service -ComputerName $Servers.instance | Select Name, Startmode, State |
Where{$_.name -like "*SQL*" -and $_.Startmode -match "Auto" -and $_.state -match "Stopped"}|Select Name,Startmode,State,#{l='Remarks';e={if($_.State -eq "Stopped"){"Failed"}}}
if (!$Servicesstate )
{
Write-Host "No Services in STOP state"
Write-Output "No Services in STOPPED state" | Out-File C:\output\SQLCHECK.STOPPED.LOG -Append
}
Else
{
echo ($Servicesstate|ft -AutoSize )
Write-Output ($Servicesstate) |FT -auto| Out-File C:\output\SQLCHECK.STOPPED.LOG -Append
}
}

parsing text-files in powershell with where and select-string operators

recently I had to solve a problem reading a large amount of logfiles and picking specific chunks of text out of them.
With some trial and error I found a working solution but I'd like to know if there are better approaches.
These logfiles contain text-blocks, each is introduced by a 'heading' followed by an unknown amount of entries and finished with an empty line. (Example below, the numbers are pseudo linenumbers)
35# logevent1
36# entry1
37# entry2
38# entry3
39#
40# logevent2
41# entry1
42# entry2
Thus I know the 'logevent'-tag I can retrieve the line with $line = $logfile | Select-String -Pattern 'logevent1' and with $lineNumber = $line | Select-Object -ExpandProperty LineNumber I have the first value to use Get-Content with range operator [$x..$y].
In my example this would be 35. But how do I get the first empty line behind the text block?
I tried to work with Select-String -Pattern '' but that gives an instant exception due to the string is empty. So I wrote he following function:
function Get-TextBlock([string]$filePath,$lineNumber)
{
$startLine = ($lineNumber -1)
$counter = 0
$emptyLines = #()
Get-Content (Get-ChildItem $filePath) | ForEach-Object {
if( $_ -eq '' ) {
$emptyLines += $counter;
}
$counter++
}
$endLine = 0
$counter = 0
while( $endLine -le $startLine) {
$endLine = ($emptyLines[$counter]); $counter++;
}
$output += ((Get-ChildItem $filePath) | Get-Content)[$startLine..$endLine]
return $output
}
As mentioned before the function works for me but I feel like there are much better and easier ways to perfrom this task.
The Output (after removing my pseudo-line-numbers ;) ) looks like this
PS F:\scripts\powershell> Get-TextBlock '.\function-test.txt' 35
logevent1
entry1
entry2
entry3
____________________________________________________________________________
Kind regards