PowerShell get detailed event information from WmiEvent (System.Management.ManagementEventWatcher) - windows

I want to get event delails like the event type and drive letter from a Windows Powershell event.
Register-WmiEvent -Class win32_VolumeChangeEvent -SourceIdentifier volumeChange -Action {
param($event)
$eventType = $event.SourceEventArgs.NewEvent.EventType # don't work
write-host $eventType
}
while (1-eq1) {} # don't exit program
This is what i want to achieve. It works on a Windows computer, but because of performance problems it don't work on a Windows tablet:
Register-WmiEvent -Class win32_VolumeChangeEvent -SourceIdentifier volumeChange
do {
$newEvent = Wait-Event -SourceIdentifier volumeChange
$eventType = $newEvent.SourceEventArgs.NewEvent.EventType
$driveLetter = $newEvent.SourceEventArgs.NewEvent.DriveName
write-host $eventType
Remove-Event -SourceIdentifier volumeChange
} while (1-eq1) # Loop until next event
Unregister-Event -SourceIdentifier volumeChange

I found out that multiple params are submitted:
Register-WmiEvent -Class win32_VolumeChangeEvent -SourceIdentifier volumeChange -Action {
param($event, $sourceEventArgs)
$eventType= $sourceEventArgs.NewEvent.EventType
write-host $eventType
}
while (1-eq1) {} # don't exit program

Related

Powershell: Failing to resume bitlocker remotely with script

I am trying to resume BitLocker protection on remote devices. See the below code:
$computers = Get-Content "C:\Users\admin_jr\Documents\bitlockerlist.txt"
$credentials = Get-Credential
foreach($computer in $computers) {
Try {
$Session = New-PSSession $computer -Credential $credentials
if (-Not ($Session)) {
Write-Error "No session is made with the specified computer, please try again"
}
Invoke-Command -Session $Session -ScriptBlock {Get-BitLockerVolume | Resume-BitLocker -Verbose}
} Catch {
Write-Error "Something went wrong"
}
}
I get the following error message:
The TPM returned an unexpected result. (Exception from HRESULT: 0x8029010C)
+ CategoryInfo : NotSpecified: (:) [Write-Error], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException,Resume-BitLocker
+ PSComputerName : *pcname*
I am currently testing this on a laptop whereby I can manually resume and suspend the Bitlocker protection but essentially want to emulate and automate this via a script on multiple pcs.
Any advice on this?

Powershell - Loop Install of Available Software Updates (SCCM)

I have the below script which I am using to run on critical desktop clients to install all available updates (quarterly) that have been deployed by SCCM.
As some deployed updates only become available when other dependent updates have been installed the script is stopping before the reboot.
I ideally want it to loop and continue to install all available updates until all have installed and then proceed to automatically reboot.
Any ideas?
Add-Type -AssemblyName PresentationCore, PresentationFramework
switch (
[System.Windows.MessageBox]::Show(
'This action will download and install critical Microsoft updates and may invoke an automatic reboot. Do you want to continue?',
'WARNING',
'YesNo',
'Warning'
)
) {
'Yes'
{
Start-Process -FilePath "C:\Windows\CCM\ClientUX\scclient.exe" "softwarecenter:Page=InstallationStatus"
$installUpdateParam = #{
NameSpace = 'root/ccm/ClientSDK'
ClassName = 'CCM_SoftwareUpdatesManager'
MethodName = 'InstallUpdates'
}
$getUpdateParam = #{
NameSpace = 'root/ccm/ClientSDK'
ClassName = 'CCM_SoftwareUpdate'
Filter = 'EvaluationState < 8'
}
[ciminstance[]]$updates = Get-CimInstance #getUpdateParam
if ($updates) {
Invoke-CimMethod #installUpdateParam -Arguments #{ CCMUpdates = $updates }
while(Get-CimInstance #getUpdateParam){
Start-Sleep -Seconds 30
}
}
$rebootPending = Invoke-CimMethod -Namespace root/ccm/ClientSDK -ClassName CCM_ClientUtilities -MethodName DetermineIfRebootPending
if ($rebootPending.RebootPending){
Invoke-CimMethod -Namespace root/ccm/ClientSDK -ClassName CCM_ClientUtilities -MethodName RestartComputer
}
'No'
# Exit-PSSession
}
}
You may loop indefinitely to start the process and stop only when $updates is $null or empty.
while($true) {
Start-Process ...
[ciminstance[]]$updates = Get-CimInstance #getUpdateParam
if ($updates) {
Invoke-CimMethod #installUpdateParam -Arguments #{ CCMUpdates = $updates }
while(Get-CimInstance #getUpdateParam){
Start-Sleep -Seconds 30
}
}
else {
break;
}
}

Downloading certain files using powershell produce corrupt files

So I have a powershell script that I wrote which crawls through a particular website and downloads all of the software hosted on the site to my local machine. The website in question is nirsoft.net, and I will include the full script below. Anyway, so I have this script that downloads all of the application files hosted on the website, when I notice something odd: while most of the file downloads completed successfully, there are several files that were not downloaded successfully, resulting in a corrupt file of 4KB:
For those of you who are familiar with Nirsoft's software, the tools are very powerful, but also constantly misidentified as dangerous because of the password cracking tools, so my guess as to why this is happening is that, since powershell's If I were to guess as to why this was happening, I would guess that, due to the fact that powershell's "Invoke-webrequest cmdlet" uses Internet Explorer's engine for its core functionality, Internet Explorer is flagging the files as dangerous and refusing to download them, thus causing powershell to fail to download the file. I confirmed this by trying to manually download each of the corrupt files using internet explorer, which marked them all as malicious. However, this is where things get strange. In order to bypass this limitation, I attempted a variety of other methods to download the file within my script, like using a pure dotnet object ( (New-object System.Net.WebClient).DownloadFile("url","file") ) and even some third party command line tools (wget for windows, wget in cygwin, etc), but no matter what I tried, not a single alternative method I used was able to download a non-corrupt file. So what I want to know is if there is a way around this, and I want to know why even third party tools are affected by this. Is there some kind of rule that any scripting tool has to use Internet Explorer's engine in order to connect to the internet or something? Thanks in advance. Oh, and one last thing before I post the script. Below is the url to one of the files that I am having difficulty in downloading via powershell, which you can use to run individual tests rather than the whole script:
enter link description here
And without further ado, here is the script. Thank again:
$VerbosePreference = "Continue"
$DebugPreference = "Continue"
$present = $true
$subdomain = $null
$prods = (Invoke-WebRequest "https://www.nirsoft.net/utils/index.html").links
Foreach ($thing in $prods)
{
If ($thing.Innertext -match "([A-Za-z]|\s)+v\d{1,3}\.\d{1,3}(.)*")
{
If ($thing.href.Contains("/"))
{
}
$page = Invoke-WebRequest "https://www.nirsoft.net/utils/$($thing.href)"
If ($thing.href -like "*dot_net_tools*")
{
$prodname = $thing.innerText.Trim().Split(" ")
}
Else
{
$prodname = $thing.href.Trim().Split(".")
}
$newlinks = $page.links | Where-Object {$_.Innertext -like "*Download*" -and ($_.href.endswith("zip") -or $_.href.endswith("exe"))}
# $page.ParsedHtml.title
#$newlinks.href
Foreach ($item in $newlinks)
{
$split = $item.href.Split("/")
If ($item.href -like "*toolsdownload*")
{
Try
{
Write-host "https://www.nirsoft.net$($item.href)"
Invoke-WebRequest "https://www.nirsoft.net$($item.href)" -OutFile "$env:DOWNLOAD\test\$($split[-1])" -ErrorAction Stop
}
Catch
{
Write-Host $thing.href -ForegroundColor Red
}
}
elseif ($item.href.StartsWith("http") -and $item.href.Contains(":"))
{
Try
{
Write-host "$($item.href)"
Invoke-WebRequest $item.href -OutFile "$env:DOWNLOAD\test\$($split[-1])" -ErrorAction Stop
}
Catch
{
Write-Host "$($item.href)" -ForegroundColor Red
}
}
Elseif ($thing.href -like "*/dot_net_tools*")
{
Try
{
Invoke-WebRequest "https://www.nirsoft.net/dot_net_tools/$($item.href)" -OutFile "$env:DOWNLOAD\test\$($split[-1])" -ErrorAction Stop
}
Catch
{
Write-Host $thing.href -ForegroundColor Red
}
}
Else
{
Try
{
Write-Host "https://www.nirsoft.net/utils/$($item.href)"
Invoke-WebRequest "https://www.nirsoft.net/utils/$($item.href)" -OutFile "$env:DOWNLOAD\test\$($item.href)" -ErrorAction Stop
}
Catch
{
Write-Host $thing.href -ForegroundColor Red
}
}
If ($item.href.Contains("/"))
{
If (!(Test-Path "$env:DOWNLOAD\test\$($split[-1])"))
{
$present = $false
}
}
Else
{
If (!(Test-Path "$env:DOWNLOAD\test\$($item.href)"))
{
$present = $false
}
}
}
}
}
If ($present)
{
Write-Host "All of the files were downloaded!!!" -ForegroundColor Green
}
Else
{
Write-Host "Not all of the files downloaded. Something went wrong." -ForegroundColor Red
}
You have two separate issues.
For anything Defender flags, it doesn't matter if you save it to disk with this or that. You could simply add an exclusion for the directory in Defender.
The other issue is pointed out by Guenther, you need to provide a referrer at least on some of the downloads. With the following changes I was able to download them all.
$VerbosePreference = "Continue"
$DebugPreference = "Continue"
$present = $true
$subdomain = $null
$path = c:\temp\downloadtest\
New-Item $path -ItemType Directory -ErrorAction SilentlyContinue | Out-Null
Add-MpPreference -ExclusionPath $path
$prods = (Invoke-WebRequest "https://www.nirsoft.net/utils/index.html").links
Foreach ($thing in $prods)
{
If ($thing.Innertext -match "([A-Za-z]|\s)+v\d{1,3}\.\d{1,3}(.)*")
{
If ($thing.href.Contains("/"))
{
}
$page = Invoke-WebRequest "https://www.nirsoft.net/utils/$($thing.href)"
If ($thing.href -like "*dot_net_tools*")
{
$prodname = $thing.innerText.Trim().Split(" ")
}
Else
{
$prodname = $thing.href.Trim().Split(".")
}
$newlinks = $page.links | Where-Object {$_.Innertext -like "*Download*" -and ($_.href.endswith("zip") -or $_.href.endswith("exe"))}
# $page.ParsedHtml.title
#$newlinks.href
Foreach ($item in $newlinks)
{
$split = $item.href.Split("/")
If ($item.href -like "*toolsdownload*")
{
Try
{
Write-host "https://www.nirsoft.net$($item.href)"
Invoke-WebRequest "https://www.nirsoft.net$($item.href)" -OutFile "$path\$($split[-1])" -ErrorAction Stop -Headers #{Referer="https://www.nirsoft.net$($item.href)"}
}
Catch
{
Write-Host $thing.href -ForegroundColor Red
}
}
elseif ($item.href.StartsWith("http") -and $item.href.Contains(":"))
{
Try
{
Write-host "$($item.href)"
Invoke-WebRequest $item.href -OutFile "$path\$($split[-1])" -ErrorAction Stop -Headers #{Referer="$($item.href)"}
}
Catch
{
Write-Host "$($item.href)" -ForegroundColor Red
}
}
Elseif ($thing.href -like "*/dot_net_tools*")
{
Try
{
Invoke-WebRequest "https://www.nirsoft.net/dot_net_tools/$($item.href)" -OutFile "$path\$($split[-1])" -ErrorAction Stop -Headers #{Referer="https://www.nirsoft.net/dot_net_tools/$($item.href)"}
}
Catch
{
Write-Host $thing.href -ForegroundColor Red
}
}
Else
{
Try
{
Write-Host "https://www.nirsoft.net/utils/$($item.href)"
Invoke-WebRequest "https://www.nirsoft.net/utils/$($item.href)" -OutFile "$path\$($item.href)" -ErrorAction Stop -Headers #{Referer="https://www.nirsoft.net/utils/$($item.href)"}
}
Catch
{
Write-Host $thing.href -ForegroundColor Red
}
}
If ($item.href.Contains("/"))
{
If (!(Test-Path "$path\$($split[-1])"))
{
$present = $false
}
}
Else
{
If (!(Test-Path "$path\$($item.href)"))
{
$present = $false
}
}
}
}
}
If ($present)
{
Write-Host "All of the files were downloaded!!!" -ForegroundColor Green
}
Else
{
Write-Host "Not all of the files downloaded. Something went wrong." -ForegroundColor Red
}
I'd also recommend you turn the download routine into a function that you can pass the relative URL portion so you don't have to repeat code several times.

How to Properly Export to CSV Using Powershell

May I know how to properly export this script to CSV?
Try {
Invoke-Command -scriptblock {Get-EventLog System -After "7/8/2017" -Before "07/28/2017" |
Where-Object {$_.EventID -eq "50" -or $_.EventID -eq "51" -or $_.EventID -eq "55" -or $_.EventID -eq "57" -or $_.EventID -eq "6008"} |
FT -Property Machinename, TimeWritten, EntryType, Source, EventID, Message -AutoSize -wrap } -computername $computer -ErrorAction Stop
}
Catch {
Write-Host $Computer "Error/RDC Problem" -ForegroundColor Red
}
Result:
Export-CSV command is not working properly when added at the end. It outputs a different set of data.
Formatting cmdlets like Format-Table don't just change the way the object is displayed, it changes the object itself into something that will display how you want it to. This is part of why it's commonly recommended not to use the formatting cmdlets in scripts or functions.
Instead, you should use the Select-Object cmdlet to limit the number of properties passed to Export-Csv.
Invoke-Command -ComputerName $computer -ErrorAction Stop -ScriptBlock {
Get-EventLog System -After "7/8/2017" -Before "07/28/2017" |
Where-Object { 50, 51, 55, 57, 6008 -contains $_.EventID } |
Select-Object -Property MachineName, TimeWritten, EntryType, Source, EventID, Message
}
try this
Try {
Invoke-Command -scriptblock {Get-EventLog System -After "7/8/2017" -Before "07/28/2017" |
Where EventID -in ("50", "51", "55", "57", "6008") |
select Machinename, TimeWritten, EntryType, Source, EventID, Message } -computername $computer -ErrorAction Stop |export-csv "c:\temp\result.csv"
}
Catch {
Write-Host $Computer "Error/RDC Problem" -ForegroundColor Red
}
or may be simply like this :
Try
{
Get-EventLog System -After "7/8/2017" -Before "07/28/2017" -ComputerName $computer |
Where EventID -in ("50", "51", "55", "57", "6008") |
select Machinename, TimeWritten, EntryType, Source, EventID, Message |export-csv "c:\temp\result.csv" -NoType
}
Catch
{
Write-Host $Computer "Error/RDC Problem" -ForegroundColor Red
}

powershell watch over folder and log changes to windows application log

As the description, I need to write a powershell script that watches over a folder. And when changes have been made(creation of file, delete, modification) I need to get these changes to get to the windows application log.
This is my code:
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "C:\Users\Administrator\Desktop\delete-file-event"
$watcher.Filter = "*.*"
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true
$action = {
New-EventLog -LogName Application -source "logs"
Write-EventLog -LogName Application -Source "logs" -EntryType Information -EventId 1 -Message "nothing in here"
$path = $Event.SourceEventArgs.FullPath
$changeType = $Event.SourceEventArgs.ChangeType
$logline = "$(Get-Date), $changeType, $path"
Add-content "C:\Users\Administrator\Desktop\delete-file-event\log.txt" -value $logline
}
Register-ObjectEvent $watcher "Created" -Action $action
Register-ObjectEvent $watcher "Deleted" -Action $action
Register-ObjectEvent $watcher "Renamed" -Action $action
while ($true) {sleep 5}
At this moment it will get to the application logs but that's because of
Code:
New-EventLog -LogName Application -source "logs"
Write-EventLog -LogName Application -Source "logs" -EntryType Information -EventId 1 -Message "nothing in here"
I would really appreciate some help here. Thanks in advance.

Resources