I have several hundred scheduled tasks. Im looking for a way to get the name of the task that called a powershell script when the script has been executed by the task scheduler. So for instance I could include that name in an alert I am sending so we know not only which server but which specific task
You can use the get-scheduledtask cmdlet. You find this cmdlet in the ScheduledTasks module.
Each returned task has an Actions Property.
E.g.
(Get-ScheduledTask)[0].Actions
To add on to Peter Schneider helpful answer which will give you details on the first task in the list. So, more specifically, to get them all, try this...
(((Get-ScheduledTask).Actions) | Select-Object *) -match 'powershell' | Select-Object -Property Id,Execute,Arguments | Format-Table -Wrap
Id Execute Arguments
-- ------- ---------
StartPowerShellJob powershell.exe -NoLogo -NonInteractive -WindowStyle Hidden -Command "Import-Module PSScheduledJob; …
Note, the '*' gest all properties and you may not want to do that, so, just explicitly select the ones you'd want
(((Get-ScheduledTask).Actions) | Select-Object -Property Id,Execute,Arguments) -match 'powershell' | Format-Table -Wrap
Related
I'm starting to work with Powershell and I've been doing some courses online. At this moment I'm stuck in a Challenge, I hope some good soul can help me with the instructions from the course.
Instructions are:
1-Find out what Windows features are installed on the server machine. (I'm remoting command to a computer named "Server")
2-Select only the data stored in the Name and InstallState columns.
3-Sort the data by the Name property in ascending (alphabetical) order.
4-Make sure the output format is set to table
5-Save the final output into a file called C:\features.txt on your desktop machine.
What I have come up with is this:
Invoke-Command -ComputerName Server -ScriptBlock{
>> Get-WindowsFeature | Select-Object -Property Name, InstallState | Sort-Object -Property Name | Format-Table
>> } | Out-File C:\features.txt
I have tried both with and without the select-object command since I know the format-table command works almost the same in this case. Thank u!
When ever I invoke a scriptblock on a remote computer i assign it to a variable and then handle the results this:
$myResults= Invoke-Command -ComputerName Server -ScriptBlock{…}
Foreach ($item in $myResults){
Write-host” $item.name /
$item.nstallState”
}
You use the pipeline rather excessively which is not wrong but for me personally still a beginner my self it is not easy to totally comprehend what each of them is exactly returning and forwarding to the next. Dont try to write a perfect line with several pips in the first attempt. Start with the smallest fastest fraction of the task. In this case yust get them all out without filter and pipelines. Then work your way from there, make little changes, use write-host to display the results and trail and error yourself to a deeper understanding of each of them. And then in the end u can chain them up.
As per my comment for example.
# 1-Find out what Windows features are installed on the server machine.
Get-WindowsFeature
# Results
<#
#>
# 2-Select only the data stored in the Name and InstallState columns.
Get-WindowsFeature |
Select-Object -Property Name, InstallState
# Results
<#
#>
# 3 - Sort the data by the Name property in ascending (alphabetical) order.
Get-WindowsFeature |
Select-Object -Property Name, InstallState |
Sort-Object -Property Name
# Results
<#
#>
# 4-Make sure the output format is set to table
Get-WindowsFeature |
Select-Object -Property Name, InstallState |
Sort-Object -Property Name |
Format-Table # though this is not needed, since table is the default for less than 5 properties.
# Results
<#
#>
<#
# 5-Save the final output into a file called C:\features.txt on your desktop
machine.
#>
Get-WindowsFeature |
Select-Object -Property Name, InstallState |
Sort-Object -Property Name |
Export-Csv -Path 'SomePathName' -NoTypeInformation -Append
# (I'm remoting command to a computer named "Server")
$Computers |
ForEach-Object {
Invoke-Command -ComputerName $PSItem.ComputerName -ScriptBlock{
Get-WindowsFeature |
Select-Object -Property Name, InstallState |
Sort-Object -Property Name |
Export-Csv -Path 'SomePathName' -NoTypeInformation -Append
}
}
I tried running the following command in PS:
Get-EventLog -LogName Security | findstr 4720
The result I got seems to be squished as if the column widths need to be adjusted. How can I view all the text that is after the ellipses (...)? See screenshot: https://i.imgur.com/fqV5qIs.png
How to view the returned info in full?
As Santiago mentioned you can use Format-Table.
Though since it looks like you're looking for a specific Event ID, I'd recommend instead of using findstr (which may return unrelated results as it's searching for '4720' anywhere in your results - unless that's your intention of course) instead target the attribute using the Where-Object cmdlet (or its' alias ?). Also, if you want a "pure" PowerShell solution I'd recommend using Select-String instead of findstr
E.g.
Get-EventLog -LogName Security | Where-Object {$_.EventID -eq 4720} | Format-Table -AutoSize -Wrap
To expand on the answer from #Novalis, Where-Object like that is definitely faster than findstr, and the Format-Table should sort out the ... you're seeing.
But to take it one step further an even faster method is to use -FilterHashtable. Specifically :
Get-WinEvent -FilterHashtable #{Logname='Security';ID=4720} | Format-Table -AutoSize -Wrap
The reason it's faster is because when using Where-Object you're asking the system for ALL of the system logs, and then once received by your script you're then filtering them out (same with findstr). FilterHashtable just requests the log entries from system that match the require event ID, so less data needs to be sent to your script.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I am working on updates for Win 7 x64 ultimate. I have a text file in which I have typed KBnnnnn one entry per line. I want sort of a script/loop to go through each entry in text file and find it in installed updates. If found append a new text file with HotFixID, Description, date etc and status='INSTALLED'. If not found, status='NOT INSTALLED'
Later I want to selectively uninstall specific HotFixes by simial loop process reading each entry from a text file and uninstalling it, updating status on screen and in another text log file. I am very new to PowerShell, tried to create a loop in cmd batch scripting using WMIC but no success yet.
Why are you not using WSUS for this? It is why it exists.
There are modules in the MS powershellgallery.com for this kind of use case well.
Find-Module -Name '*WSUS*' | Format-Table -AutoSize
Version Name Repository Description
------- ---- ---------- -----------
2.3.1.6 PoshWSUS PSGallery PowerShell module to manage a WSUS Server. Support site: https://github.com/proxb/PoshWSUS/
1.1.0 ecs.wsus PSGallery This Windows PowerShell module contains ECS.WSUS funtions
0.4.4 PSWsusSpringClean PSGallery Give your WSUS server a thorough spring cleaning
0.9.0 PSWSUSMigration PSGallery Powershell module to help WSUS (Windows Server Update Services) server migration. Support site: https://github.com/reiikei/PSWSUSMigration
I am working on updates for Win 7 x64 ultimate.
So, what version of PowerShell are you using on Win7?
I have a text file in which I have typed KBnnnnn one entry per line.
OK, a standard file that can be easily read using Import-Csv or Get-Content. Yet, why are you doing this? There is a cmdlet called Get-HotFix specifically for this.
# All Help topics and locations
Get-Help about_*
Get-Help about_Functions
Get-Help about* | Select Name, Synopsis
Get-Help about* |
Select-Object -Property Name, Synopsis |
Out-GridView -Title 'Select Topic' -OutputMode Multiple |
ForEach-Object { Get-Help -Name $_.Name -ShowWindow }
explorer "$pshome\$($Host.CurrentCulture.Name)"
# Get parameters, examples, full and Online help for a cmdlet or function
# Get a list of all functions
Get-Command -CommandType Function |
Out-GridView -PassThru -Title 'Available functions'
# Get a list of all commandlets
Get-Command -CommandType Cmdlet |
Out-GridView -PassThru -Title 'Available cmdlets'
# get function / cmdlet details
Get-Command -Name Import-Csv -Syntax
(Get-Command -Name Import-Csv).Parameters.Keys
Get-help -Name Import-Csv -Full
Get-help -Name Import-Csv -Online
Get-help -Name Import-Csv -Examples
Get-Command -Name Get-Content -Syntax
(Get-Command -Name Get-Content).Parameters.Keys
Get-help -Name Get-Content -Full
Get-help -Name Get-Content -Online
Get-help -Name Get-Content -Examples
Get-Command -Name Get-Hotfix -Syntax
(Get-Command -Name Get-Hotfix).Parameters.Keys
Get-help -Name Get-Hotfix -Full
Get-help -Name Get-Hotfix -Online
Get-help -Name Get-Hotfix -Examples
I want sort of a script/loop
Sure, you can do this.
About ForEach
Each of the above help files has examples of loops.
to go through each entry in text file and find it in installed
updates.
OK, this is a common thing. A PowerShell very beginner thing, with lots of articles, samples and videos all over the web for this and shown in the help cmdlet, resources, etc., shown.
If found append a new text file with HotFixID, Description, date etc.,
and status='INSTALLED'. If not found, status='NOT INSTALLED'
Again, nothing new or complicated here and again a very common thing and done via the -Append switch or the Add-Content cmdlet.
Get-Command -Name Add-Content -Syntax
(Get-Command -Name Add-Content).Parameters.Keys
Get-help -Name Add-Content -Full
Get-help -Name Add-Content -Online
Get-help -Name Add-Content -Examples
later I want to selectively uninstall specific HotFixes by simial loop
process reading each entry from a text file and uninstalling it,
Again, nothing new or complicated here and again a very common thing. You do this via a comparison block/command in your code.
About Comparison Operators
updating status on screen and in another text log file.
Again, nothing new or complicated here and again a very common thing. This is what Out-File or Export-Csv, or Start-Transcript or writing your own logger is for and using progress bars. Lots of articles, blogs, videos ho how to do this.
Script Write-Log PowerShell Logging Function
Get-Command -Name Write-Progress -Syntax
(Get-Command -Name Write-Progress).Parameters.Keys
Get-help -Name Write-Progress -Full
Get-help -Name Write-Progress -Online
Get-help -Name Write-Progress -Examples
I am very new to PowerShell, tried to create a loop in cmd batch
scripting using WMIC but no success yet.
OK, this is fine. It means you should spend time learning it first and there are plenty of free text-based and video-based (YouTube videos, MSDN videos, etc.) for you to use. All it requires is that you search for it, use them as-is and or tweak as needed.
'powershell windows hotfix management'
'Beginning PowerShell'
'Intermediate PowerShell'
'Advanced PowerShell'
'PowerShell file and folder management'
'PowerShell hotfix report'
Sample scripts
'powershellgallery.com hotfix management'
'wmic find hotfix'
'vbscript wmic hotfix management'
The question here is, why are you using WMIC, vs Powershell directly? Hence the cmdlets above. One can use WMIC without ever using PowerShell at all, in .bat/cmd/vbs files as has been done for years.
You say you've done batch file programming, It's good to see you dip into the PowerShell pool, but that does not mean you can't stick with batch to do what you need and then convert that to PowerShell now or later.
Update based on you code comment
If you did this in the console/ISE/VSCode, it just works as it would from cmd.exe
wmic qfe get hotfixid > d:\temp\QfElist.txt
Get-content -Path 'd:\temp\QfElist.txt'
<#
Results
KB4537572
KB4513661
...
#>
But you could have just done this and gotten something far more useable
Get-HotFix
<#
# Results
Source Description HotFixID InstalledBy InstalledOn
------ ----------- -------- ----------- -----------
LP70 Update KB4537572 NT AUTHORITY\SYSTEM 11-Mar-20 00:00:00
LP70 Update KB4513661 09-Sep-19 00:00:00
LP70 Security Update KB4515383 09-Sep-19 00:00:00
...
#>
Comparing this against a file is just as simple. Let's say your file looks like this.
$KBCheckList = '
KB4537572
KB4513661
KB4515400
' | Out-File -FilePath 'D:\Temp\KBCheckList.txt'
Now read the file, using this
Get-Content -Path 'D:\Temp\KBCheckList.txt'
<#
# Results
KdId
KB4537572
KB4513661
KB4515400
#>
or this
Import-Csv -Path 'D:\Temp\KBCheckList.txt'
<#
# Results
WARNING: One or more headers were not specified. Default names starting with "H" have been used in place of any missing headers.
H1
--
KB4537572
KB4513661
KB4515400
#>
You can see the difference is minor (visually) but Csv file needs a header (and really should be properly formatted first). Either add it to the top of the file or add it on the fly
Import-Csv -Path 'D:\Temp\KBCheckList.txt' -Header 'KBID'
<#
# Results
KBID
----
KB4537572
KB4513661
KB4515400
#>
All the above is just educational stuff for you. You only really need one of the two below, or similar.
Now just use the file. Read in a loop and use if/then or try/catch statement to get results
Import-Csv -Path 'D:\Temp\KBCheckList.txt' -Header 'KBID' |
ForEach {
$PSItem.KBID
}
<#
# Results
KB4537572
KB4513661
KB4515400
#>
or just compare the file list to the results of the cmdlet
$QfeData = Get-Hotfix
$KBCheckList = Import-Csv -Path 'D:\Temp\KBCheckList.txt' -Header 'KBID'
Compare-Object -ReferenceObject $QfeData.HotFixID -DifferenceObject $KBCheckList.KBID
<#
# Results
InputObject SideIndicator
----------- -------------
KB4515400 => *** this means that this ID is only in the DifferenceObject which is your file, thus not installed.
KB4515383 <=
KB4516115 <=
KB4517245 <=
KB4521863 <=
KB4524244 <=
KB4524569 <=
KB4525419 <=
KB4528759 <=
KB4537759 <=
KB4538674 <=
KB4541338 <=
KB4551762 <=
#>
I have the following code, It's work when I use directly within powershell:
Get-WmiObject win32_operatingsystem | select #{LABEL=’LastBootUpTime’;EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)
And it returns:
LastBootUpTime
--------------
14/09/2019 10:41:50
But when I use the command within a Powershell script .ps1 with invoke-command the output returns more informations:
LastBootUpTime PSComputerName RunspaceId
-------------- -------------- ----------
9/14/2019 10:41:50 AM 192.168.0.20 af08d2d8-c4f1-4f85-9d6c-e3f4ffe475c6
Why this happen?
If possible, I'd like without the header LastBootUpTime too.
Invoke-Command will always return additional information, in this case where the command was run and the runspace id. You can always get results into a variable and simply print out the property you want.E.g.
$result = invoke-command {your-command}
$result.LastBootUpTime
or for short
(invoke-command {your-command}).LastBootupTime
Note that when you are using wmi, you do not need to necessarily use invoke-command, you can also directly pass -computer parameter to it to run the command against a remote computer:
Get-WmiObject win32_operatingsystem -computer "remote_computer_name"
Since you're ultimately only interested in the (transformed) property value, there's no need to use Select-Object (whose alias is select) at all - use ForEach-Object instead:
Get-WmiObject Win32_OperatingSystem |
ForEach-Object { $_.ConvertToDateTime($_.LastBootUpTime) }
Note: The extra properties you saw, added by a remote Invoke-Command call with a -ComputerName argument (described below), are still technically present on the result, but they won't display.
That said, the WMI cmdlets were deprecated in PowerShell version 3. Using Get-CimInstance in lieu of Get-WmiObject actually makes the .ConvertToDateTime() call unnecessary (the .LastBootUpTime now directly contains a [datetime] instance), in which case you can simply use Select-Object's -ExpandProperty parameter in order to return the property value only (rather than a [pscustomobject] instance with the requested property):
Get-CimInstance CIM_OperatingSystem | Select-Object -ExpandProperty LastBootUpTime
Note: Get-CimInstance directly supports a -ComputerName argument, so you don't need Invoke-Command -ComputerName for the invocation; unlike the firewall-unfriendly DCOM protocol that the WMI cmdlets use, the CIM cmdlets use the same, firewall-friendly transport as PowerShell remoting.
Or, more succinctly and efficiently, especially in a case such as this where the command returns only a single object, use direct property access:
(Get-CimInstance CIM_OperatingSystem).LastBootUpTime
This answer contrasts the pros and cons of these two approaches and shows other alternatives.
As for what you tried, which generally relates to:
Managing the origin properties automatically added by remote operations:
In remoting scenarios, PowerShell decorates the objects returned with additional properties that provide origin information. These properties are (mostly) of type NoteProperty and are added:
when PowerShell remoting is involved - such as via Invoke-Command -ComputerName in your case.
when CIM cmdlets such as Get-CimInstance are directly used remotely, such as with the -ComputerName parameter.
These properties are:
.PSComputerName (the name of the remote computer on which the code was executed)
Note: On objects returned from remote CIM calls, .PSComputerName appears as a regular property (type Property), not a NoteProperty.
The associated hidden .PSShowComputerName property, which defaults to $true, which explains why you saw a PSComputerName column in the display output.
If you capture the objects before printing them to the screen, you can set the property to $false on them, in which case their .PSComputerName property won't show (but will still be there) - however, the .RunspaceId property may - situationally - still show, and would have to be explicitly excluded - see below.
PowerShell remoting only (not remote CIM calls): .RunspaceId (the ID of the remote runspace)
To exclude these from local display / presence on the object, use the following techniques:
If you're only interested in select properties, make the Select-Object call locally, which, by virtue of locally constructing new [pscustomobject] instances with the properties of interest only, implicitly excludes the remoting-added properties:
Invoke-Command -ComputerName ... { ... } |
Select-Object Name, LastBootUpTime # LOCAL call to Select-Object
If you're interested in all properties except the remoting-added ones, use Select-Object -ExcludeProperty to eliminate them explicitly:
# Get remote output, then locally exclude the remoting-added properties.
Invoke-Command -ComputerName ... { ... } |
Select-Object * -ExcludeProperty PSComputerName, PSShowComputerName, RunSpaceId
Note: Select-Object generally returns [pscustomobject] instances whose properties are static copies of the input objects and which lack the input type's methods.
I found one way! if someone to need here is:
Get-WmiObject win32_operatingsystem | select #{LABEL=’LastBootUpTime’;EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}}|Select-Object -ExpandProperty lastbootuptime
Here is how I used (I'm creating a report in HTML for my database)
write-output "<p> Horario do Ultimo boot: $(Get-WmiObject win32_operatingsystem | select #{LABEL=’LastBootUpTime’;EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}}|Select-Object -ExpandProperty lastbootuptime)</p>"
The output was (in my language and region):
Horario do Ultimo boot: 09/14/2019 10:41:50
I made this code to kill a task. With Get-VBRJob i get all the backup jobs and their ID, then I isolate the job name imput, then filter just leave the ID and last it delete the header. This variable result is not working on the wmic command im using. I guess i need to convert the variable content in something?. Thanks!
$JobName = Read-Host "Enter Job name"
$JobID = Get-VBRJob | select name, ID | Where {$_.name -like $JobName} | select ID | Format-Table -HideTableHeaders
wmic Path win32_process Where "CommandLine Like '%$JobID%'" Call Terminate
It looks like there's blank lines above and below the id. I think you want
| select -expand id
instead with no format-table. And the id must appear in the commandline. You wouldn't normally store format-table output to a variable.
Btw, instead of wmic, you can use
get-wmiobject win32_process | where commandline -match $jobid | remove-wmiobject