I am trying to convert ForwardedEvents.evtx file to CSV format using below command in powershell(opened in admin mode). But I see System.AccessViolationException Attempt to read or write protected memory error. Attached screenprint, pls help.
Get-WinEvent -Path C:\Windows\System32\winevt\Logs\ForwardedEvents.evtx |Export-Csv ConvertedForwardedEvents.csv
Related
The task given was to create a way for our staff to see who has the file open that they want to use, as Windows says it is either locked and doesn't name the person who has it locked, or it displays the person who made the file but not the person who currently has it open.
I can look it up in Computer Management on the fileserver, but were are hoping to speed up this for the end users.
I've written this powershell script on our fileserver and it works perfectly, I have this running every 5 minutes in Task Scheduler with administrative permissions:
get-smbopenfile -ClientUserName * |select clientcomputername,clientusername,path | Out-File -Encoding utf8 "S:\LockedFiles.txt" -width 300
The output looks like this:
clientcomputername clientusername path
------------------ -------------- ----
IPADDRESS DOMAIN\USERNAME S:\FOLDER\FILE.FILEEXTENSION
What I really want to do now is get the computer name rather than the IP address, just in case staff are logged into multiple machines at the same time.
I wondered if ClusterNodeName or PSComputerName would provide this, but the returned data is always blank.
I thought about this and below is one option (the first line is pseudocode), but as I see it that would mean recursively altering the piped data or reading in piped data, which I'm not even sure how to do.
$ipaddress = IPADDRESS
$Workstation = [System.Net.Dns]::GetHostByName($ipaddress)
Write-Host $Workstation.HostName
Anyone have any ideas on how I can do this? Is there a better way?
I assume you're looking to add a new property to your output object that has the resolved DNS Name from the IP Address found in the ClientComputerName property. For this you use Resolve-DnsName to attempt the name resolution and a Try Catch in case it fails to capture the exception message. For the export I would recommend you to use Export-Csv.
Get-SmbOpenFile -ClientUserName * | ForEach-Object {
$dnsName = try {
(Resolve-DnsName $_.ClientComputerName -ErrorAction Stop).NameHost
}
catch {
[ComponentModel.Win32Exception]::new($_.Exception.NativeErrorCode).Message
}
[pscustomobject]#{
ClientIpAddress = $_.ClientComputerName
ResolvedHostName = $dnsName
ClientUserName = $_.ClientUserName
Path = $_.Path
}
} | Export-Csv "S:\LockedFiles.csv" -Encoding utf8 -NoTypeInformation
I'm trying to gracefully exit the program if the username/password is incorrect or (ORA-01017) but the script hangs when getting an error. My proposed error is in the try section of the code then the entire script hangs. I thought the catch is suppose to throw the exception. Ideally I will create a for loop that will connect to each database and if there is an error just capture the error and go on to the next. But right now just testing the try/catching the error option. Also, I'm encrypting the password. Any ideas or suggestions
enter code here
function Start-Something
{
$User = Read-Host -Prompt 'Input the Oracle database user name'
$psswd = Read-Host -Prompt 'Input Oracle database Password:' -AsSecureString
$cryptpasswd = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($psswd))
Write-Host "###############################################"
Write-Host Connecting to Oracle Database: testdb -ForegroundColor Green
sqlplus -s $User/$cryptpasswd#$line '#C:\Users\my\Documents\Scripts\oracledbinfo.sql'
Write-Host "###############################################"
Write-Host " ###########################################"
}
try
{
Start-Something
}
catch
{
Write-Output "Something threw an exception"
Write-Output $_
}
try
{
Start-Something -ErrorAction Stop
}
catch
{
Write-Output "Something threw an exception or used Write-Error"
Write-Output $_
}
Try/Catch does not hang. Looks like this line of code is waiting for input:
sqlplus -s $User/$cryptpasswd#$line '#C:\Users\my\Documents\Scripts\oracledbinfo.sql'
To verify run the codeblock of the function directly in the shell.
Currently you ask for the password and convert the string entered to a secureString Read-Host -Prompt 'Input Oracle database Password:' -AsSecureString then you probably try to convert the value back to string, because sqlplus won't accept a secureString. But you missed a part =(System.Runtime.InteropServices.Marshal]::PtrToStringAuto())...
Anyways, here are some tips for you:
Take a look at the oracle .NET provider its the better choice on PowerShell.
If you want the user to input credentials use the get-credential cmdlet. By doing so you get a credential object back which you can use to authenticate or by calling the method getNetworkCredential() to get the password in cleartext.
Implement also a try/catch block within the function and return errors always with write-error and learn about output streams. try/Catch will only consider terminating errors, but sqlplus won't give you that -> oracle .NET provider.
Preface:
Toni's answer makes a good point that the apparent hang may be due to sqlplus waiting for an interactive response. If that is the case, that problem must be solved first.
A simpler way to convert a SecureString instance to plain text - which notably defeats the (limited) security benefits that SecureString provides (on Windows only) - is the following:
[pscredential]::new('unused', $psswd).GetNetworkCredential().Password
As an inconsequential aside, with respect to your approach: it should be [Runtime.InteropServices.Marshal]::PtrToStringBSTR(...), not [Runtime.InteropServices.Marshal]::PtrToStringAuto(...)
As of PowerShell 7.2.x, calls to external programs (such as sqlplus) never cause a (statement-)terminating error[1] that you can trap with try / catch
A potential future feature - which in preview versions of v7.3 is available as an experimental feature that may or may not become official - may allow better integration with PowerShell's error handling, by setting the $PSNativeCommandUseErrorActionPreference preference variable to $true.
Unfortunately, as of v7.3.0-preview.8, the error that is reported in response to a nonzero exit code (see below) is unexpectedly a non-terminating error, which means it can not be trapped with try / catch by the caller - see GitHub issue #18368.
To determine if a call to an external program call failed, examine its process exit code, as reflected in the automatic $LASTEXITCODE variable afterwards.
By convention, exit code 0 signals success, any nonzero value failure.
Therefore:
# Note: Write-Host calls omitted for brevity.
function Start-Something {
$User = Read-Host -Prompt 'Input the Oracle database user name'
$psswd = Read-Host -Prompt 'Input Oracle database Password:' -AsSecureString
$psswdClearText = [pscredential]::new('unused', $psswd).GetNetworkCredential().Password
# Invoke sqlplus.
# !! AS NOTED, YOU MAY HAVE TO MODIFY THIS COMMAND TO PREVENT AN INTERACTIVE PROMPT.
# Stderr output from this call, if any, goes directly to the display.
sqlplus -s $User/$psswdClearText#$line '#C:\Users\my\Documents\Scripts\oracledbinfo.sql'
# If sqlplus reported a nonzero exit code,
# throw a script-terminating error that the caller must handle with try / catch.
if ($LASTEXITCODE -ne 0) {
throw "sqlplus signaled failure: exit code is: $LASTEXITCODE"
}
}
try {
Start-Something
}
catch {
# Convert the script-terminating error into a non-terminating one.
$_ | Write-Error
}
[1] There are only two exceptions: (a) If the external program cannot even be invoked, e.g., because its name/path is misspelled or it isn't installed. Or (b), due to a bug, present up to PowerShell 7.1, where the combination of redirecting stderr output (2> or *>) with $ErrorActionPreference = 'Stop' unexpectedly caused a script-terminating error if there's actual stderr output - see this answer.
I'm trying to automatize the process of storing BitLocker Keys to ADDS.
I wanna be able to run the following script at logon, in order to do that, as the OS is deployed through WDS which already encrypts the drive:
$BitVolume = Get-BitLockerVolume -MountPoint $env:SystemDrive
$RecoveryKey = $BitVolume.KeyProtector | Where-Object { $_.KeyProtectorType -eq 'RecoveryPassword' }
Backup-BitLockerKeyProtector -MountPoint $env:SystemDrive -KeyProtectorId $RecoveryKey.KeyProtectorID
BackupToAAD-BitLockerKeyProtector -MountPoint $env:SystemDrive -KeyProtectorId $RecoveryKey.KeyProtectorID
I always get access denied as this has to run as admin...
Is there any command I can use prior the code to run it as admin?
I've googled but I found no useful info to actually do this...
As for the access denied part... as was already sated, you need to start your PowerShell session as an admin. However, as a point of note about your code, you are only targeting the system/os volume... which may not be the only volume that's encrypted. If you want to programmatically backup all of the encrypted volumes, may I suggest one of the two following options...
One-liner:
Get-BitLockerVolume | where {$_.VolumeStatus -like "FullyEncrypted"} | foreach {foreach($Key in $_.KeyProtector){if($Key -like "RecoveryPassword"){Backup-BitLockerKeyProtector -MountPoint $_.mountpoint -KeyProtectorId $key.KeyProtectorId}}}
Or, if you prefer something a little bit easier to read...
Script Block:
foreach ($BLV in Get-BitLockerVolume){
if ($BLV.VolumeStatus -like "FullyEncrypted"){
foreach ($Key in $BLV.KeyProtector) {
if ($Key -like "RecoveryPassword") {
Backup-BitLockerKeyProtector -MountPoint $BLV.MountPoint -KeyProtectorId $Key.KeyProtectorId
}#if
}#foreach
}#if
}#foreach
Neither is super eloquent... but, with this method it will grab all of the encrypted volumes on the system and add them to AD. You would need to modify the code slightly to add the AAD backup option you cited of course.
P.S. I'm only responding because I recently had to solve this problem of multi-volume backups as a one-liner solution and figured I would share it since your post was a top search result when I looked for a pre-canned solution. Cheers! :)
In Windows RT on a Surface tablet, I'm running a VB script that fails on the first line which is:
Set WshShell = WScript.CreateObject("WScript.Shell")
The error message says:
Could not create object WScript.Shell with the error code: 80070005
This seems to be a generic error code having to do with access permissions. Any ideas?
I am running with admin privileges.
Windows RT (also known as Windows 8 RT, Windows 8.1 RT, and Surface RT) uses User Mode Code Integrity (UMCI) to restrict the software that is allowed to run.
In the case of VBScript, the Code Integrity component of UMCI only allows creation of "enlightened" COM objects.
"Which COM objects are enlightened?" you ask. Good question. Let's use PowerShell on our Windows RT device to help us find out.
$arrInstances = #(Get-WMIObject -ClassName 'Win32_COMSetting')
$arrCOMObjectProgIDs = #($arrInstances | Where-Object { $null -ne $_.ProgId } |
ForEach-Object { $_.ProgId })
$ErrorActionPreference = [System.Management.Automation.ActionPreference]::SilentlyContinue
$result = #($arrCOMObjectProgIDs | ForEach-Object { if (New-Object -ComObject $_) { $_ } })
$result
On my fully-patched Surface 2 device, as of today, 2021-Jan-17, the only enlightened COM objects with a ProgID (i.e., the only ones callable from VBScript on Windows RT) are:
Scripting.FileSystemObject
VBScript.RegExp
Scripting.Dictionary
It is not possible to create other VBScript objects (e.g., WScript.Shell, WScript.Network, WinNTSystemInfo, Wbemscripting.SWbemLocator, etc.) on Windows RT due to User Mode Code Integrity (UMCI).
For a more-robust version of the above code, check out my script "Get-COMObjectsProgIDsAllowedToLaunch.ps1" posted to my GitHub repo: https://github.com/franklesniak/PowerShell_Resources
I've seen in a few places people commenting that RT doesn't allow VBScript to run WScript.Shell, though I've not found any official documentation to that effect.
It may just be that the script needs to run with Admin privileges.
I use the following command to tail a logfile on a w2k8 server from a windows8 client pc:
get-content "file" -wait
The log file shows up and it sits there patiently waiting for new lines to be added,
but new lines never show up when they are added.
It worked fine on w2k3 server but somehow tailing on w2k8 server does not work.
The log file is updated from a C# service:
Trace.Listeners.Add(new TextWriterTraceListener(logFileName, "fileListener"));
Trace.WriteLine(....)
Does anybody know what to do about this?
I repro'd the issue on my WS08 system using Trace class. I tried both Trace.Flush() and writing lots of data (100K) and neither caused get-content -wait to respond.
However I did find a workaround. You'd have to update your C# program. (While experimenting I came to the conclusion that gc -wait is pretty fragile.)
$twtl= new-object diagnostics.TextWriterTraceListener "C:\temp\delme.trace",
"filelistener"
[diagnostics.trace]::Listeners.add($twtl)
# This sequence would result in gc -wait displaying output
[diagnostics.trace]::WriteLine("tracee messagee thingee")
[diagnostics.trace]::flush()
# Here I did file name completion such that c:\temp\delme.trace was in the
# completion list.
# In other words I typed something like d and pressed tab
# And this worked every time
# After searching for quite a while I finally found that
# get-itemproperty c:\temp\d*
# produced the same effect. The following sequence always worked:
# (without requiring a tab press)
[diagnostics.trace]::WriteLine("tracee messagee thingee")
[diagnostics.trace]::flush()
get-itemproperty c:\temp\d*
# To finish up
[diagnostics.trace]::Listeners.remove($twtl)
$twtl.close()
$twtl.dispose()
I think there's a bug somewhere. I suggest filing it on the Connect website.