Powershell & bcdedit: Identify recovery partitions - powershell

I am trying to script the elimination/backup of the OEM partition (which just brings back the system to an outdated version of no practical use).
On many systems, using DISKPART list partition returns more recovery type partitions: one is the official Microsoft Recovery Tools partition (WinRE) and others come from the OEMs.
The first step is to safely identify the position of the WinRE partition. I did not find any straight way in bcdedit or PS other than:
$renv=(bcdedit /enum "{default}" | Select-String "^recoverysequence" | Out-String | Select-String "{.+}").Matches.Value
(bcdedit /enum $renv | Select-String "^device" | Out-String | Select-String "\[.+\]").Matches.Value
This returns a string like:
[\Device\HarddiskVolume1]
where the volume number is the partition to use in Diskpart. (Remaining recovery partitions and the OEM type partitions can be backupped).
Is this the correct procedure to identify the WinRE partition?
Any more straight and/or better approach?

There's a command line tool called ReagentC, and it's in the path, so you can call it from any administrative command prompt.
reagentc /info
...will produce some output like:
Windows RE status: Enabled
Windows RE location: \\?\GLOBALROOT\device\harddisk0\partition4\Recovery\WindowsRE
Boot Configuration Data (BCD) identifier: 496c58c4-71cb-11e9-af8f-001c42903d2e
Recovery image location:
Recovery image index: 0
Custom image location:
Custom image index: 0
Also, if you're writing code to do the work, you can discover the recovery partition by calling a winapi function to do the work. It's an obnoxiously complicated api to call...but for what it's worth, it's DeviceIOControl with the control code of IOCTL_DISK_GET_PARTITION_INFO_EX. If you're not using C or some language that defines unions, this is a pain. The structure you get back varies with whether the disk is GPT or MBR format.
If the disk is MBR, the returned partition type will be 0x27, and if it's a GPT drive the partition type will be the guid: de94bba4-06d1-4d40-a16a-bfd50179d6ac.

Aside from streamlining the Select-String with a Lookbehind-RE
I dont't see a better approach ATM.
$renv=(bcdedit /enum "{default}" | Select-String "(?<=^recoverysequence\s+)({.+})").Matches.Value
(bcdedit /enum $renv | Select-String "(?<=^device.+)\[.+\]").Matches.Value
[\Device\HarddiskVolume5]

Related

How to concatenate characters after recognition and interception in PowerShell

I want to turn the following input:
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice:
ASL Module "com.apple.cdscheduler" claims selected messages.
Those messages may not appear in standard system log files or in the ASL database.
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice:
ASL Module "com.apple.install" claims selected messages.
Those messages may not appear in standard system log files or in the ASL database.
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice:
ASL Module "com.apple.callhistory.asl.conf" claims selected messages.
Those messages may not appear in standard system log files or in the ASL database.
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice:
ASL Module "com.apple.authd" sharing output destination "/var/log/asl" with ASL Module "com.apple.asl".
Output parameters from ASL Module "com.apple.asl" override any specified in ASL Module "com.apple.authd".
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice:
ASL Module "com.apple.mkb" sharing output destination "/private/var/log/keybagd.log" with ASL Module "com.apple.mkb.internal".
Output parameters from ASL Module "com.apple.mkb.internal" override any specified in ASL Module "com.apple.mkb".
into the following output:
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice:ASL Module "com.apple.cdscheduler" claims selected messages.Those messages may not appear in standard system log files or in the ASL database.
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice:ASL Module "com.apple.install" claims selected messages.Those messages may not appear in standard system log files or in the ASL database.
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice:ASL Module "com.apple.callhistory.asl.conf" claims selected messages.Those messages may not appear in standard system log files or in the ASL database.
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice:ASL Module "com.apple.authd" sharing output destination "/var/log/asl" with ASL Module "com.apple.asl".Output parameters from ASL Module "com.apple.asl" override any specified in ASL Module "com.apple.authd".
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice:ASL Module "com.apple.mkb" sharing output destination "/private/var/log/keybagd.log" with ASL Module "com.apple.mkb.internal".Output parameters from ASL Module "com.apple.mkb.internal" override any specified in ASL Module "com.apple.mkb".
That is, the indented lines should be joined to the preceding non-indented line.
I would first make sure it's a multi-line string (rather than an array of strings), then use RegEx to split based on the date/time stamp, and for each multi-line bit passed trim any whitespace from a line, and join the lines together into one line. That can be done with something like this
$LogText -join "`n" -split '[\r\n]+\s*(?=\w+ \d+ \d+:\d+:\d+)'|
ForEach-Object {$_.trimstart() -replace '[\r\n]+\s*'}
Assuming that your May ... lines have no leading whitespace:
If the file is small enough to fit into memory as a whole, combine Get-Content -Raw with the regex-based -replace operator (redirect the output to a file as needed; if the input text is already in memory, simply use it as the LHS):
(Get-Content -Raw file.log).TrimEnd() -replace '\r?\n\s+', ' '
Otherwise, use a switch statement with the -File and -Regex parameters:
& {
$mergedLine = ''
switch -Regex -File file.log {
'^\S' { # 'May ...' line, no leading whitespace.
if ($mergedLine) { $mergedLine } # output previous
$mergedLine = $_
}
default { # Subsequent, indented line (leading whitespace)
$mergedLine += ' ' + $_.TrimStart()
}
}
$mergedLine # output final merged line
}
Note:
For readability, the solutions above place a space char. between the merged (joined) lines; remove the use of ' ' from the code above to join them without a separator (as in the sample output in your question).
You can pipe the & { ... } solution to Set-Content for output, though if performance is paramount, you may want to use the System.IO.StreamWriter .NET type for faster writing, as shown in this answer.
An equivalent awk-based solution can be found in this answer to your follow-up question about a native macOS solution.

Parsing Windows Defender event log in PowerShell

I need to parse Windows Defender event log. With this command
Get-WinEvent -LogName "Microsoft-Windows-Windows Defender/Operational" | Where-Object { $_.LevelDisplayName -ne "Information" } | Select-Object -ExpandProperty Message
I get this output:
Windows Defender Antivirus has detected malware or other potentially unwanted software.
For more information please see the following:
https://go.microsoft.com/fwlink/?linkid=37020&name=Trojan:Win32/TFTPD32&threatid=12892&enterprise=0
Name: Trojan:Win32/TFTPD32
ID: 12892
Severity: Severe
Category: Trojan
Path: file:_\\server\share\path\file1.exe::$DATA; file:_\\server\share\path\file2.exe::$DATA; file:_\\server\share\path\file3.exe::$DATA;
Detection Origin: Network share
Detection Type: Concrete
Detection Source: Real-Time Protection
User: DOMAIN\user
Process Name: C:\Windows\SMSProxy\Microsoft.StorageMigration.Proxy.Service.exe
Signature Version: AV: 1.335.1263.0, AS: 1.335.1263.0, NIS: 1.335.1263.0
Engine Version: AM: 1.1.18000.5, NIS: 1.1.18000.5
When there are multiple files and the line starting with Path: is very long, it is truncated. Not the message property, but only the line.
When I see the record using Event Log viewer, the line is complete.
Is there a way to get full length of the line?
I need to get lines with Name: and Path: from the Message property (multi-line string) only.
How can I get it using e.g. RegEx ^\s+(Name|Path): ?
Update:
I mishmatched event log records, even in Event Log the line Path is truncated.
The second part of the question remains: How to get only some lines from multiline property?

Extracting values from AnalyzeComponentStore?

Hello everyone and thanks in advance for the possible answers.
Where I work we have different WS2016 virtual machines and we read that the updates could be a pain due to the very long time they could take and we can't stay a lot with the services down (we have several virtual machines to update soon).
In the same thread we read an advice: cleaning the WinSXS folder could drastically reduce this time.
WS2016 already has this scheduled but it has got a 1 hour timeout so if it takes more than that the process gets killed.
The solution is creating the schedule manually so we made a script for this that checks the current date and the last update date and, if the difference is more than 30 days, it runs the command:
dism.exe /Online /Cleanup-Image /AnalyzeComponentStore
and then the command:
dism.exe /Online /Cleanup-Image /StartComponentCleanup
Now the real question...One of the results of AnalyzeComponentStore is:
Component Store Cleanup Recommended
And the answer could be Yes or No
Is there a way to check if this value is "Yes" (so launch the StartComponentCleanup) or "No" (so exit from the script)?
Thanks again!
#Doug Maurer...this is the result of the AnalyzeComponentStore
PS C:> dism.exe /Online /Cleanup-Image /AnalyzeComponentStore
Deployment Image Servicing and Management tool
Version: 10.0.14393.3750
Image Version: 10.0.14393.3241
[===========================99.7%========================= ]
Component Store (WinSxS) information:
Windows Explorer Reported Size of Component Store : 8.08 GB
Actual Size of Component Store : 7.94 GB
Shared with Windows : 6.12 GB
Backups and Disabled Features : 1.49 GB
Cache and Temporary Data : 323.47 MB
Date of Last Cleanup : 2016-09-12 13:40:35
Number of Reclaimable Packages : 0
Component Store Cleanup Recommended : Yes
The operation completed successfully.
PS C:>
There are several ways to achieve this, I will list two and you can choose the one you like better. Others may offer alternative approaches.
First using Select-String - simply pipe the output into select string
$output = #'
Deployment Image Servicing and Management tool Version: 10.0.14393.3750
Image Version: 10.0.14393.3241
[===========================99.7%========================= ]
Component Store (WinSxS) information:
Windows Explorer Reported Size of Component Store : 8.08 GB
Actual Size of Component Store : 7.94 GB
Shared with Windows : 6.12 GB
Backups and Disabled Features : 1.49 GB
Cache and Temporary Data : 323.47 MB
Date of Last Cleanup : 2016-09-12 13:40:35
Number of Reclaimable Packages : 0
Component Store Cleanup Recommended : Yes
The operation completed successfully.
'#
$output | Select-String "Component Store Cleanup Recommended : (\w*)" | foreach {$_.matches.groups[1].value}
I used the outvariable paremeter of Foreach, you could also just assign normally
$cleanup = $output | Select-String "Component Store Cleanup Recommended : (\w*)" | foreach {$_.matches.groups[1].value}
Second suggestion is to use -Match
$cleanup = if($output -match "Component Store Cleanup Recommended : (\w*)"){$matches[1]}
Both will end up setting $cleanup to the yes/no value you're after.
Get-Variable cleanup
Name Value
---- -----
cleanup {Yes}
Now you can simply check if it's yes and run the cleanup if so.
if($cleanup -eq 'yes'){"run cleanup code"}

How to remove unused temp files from Google Cloud SQL managed Postgres?

We've moved to Google Cloud SQL, created couple of databases and imported lots of data. Alongside it was a pretty large amount of queries which were interrupted here and there which have left some garbage in form of temp files. And the storage usage went far above 1TB.
postgres=> SELECT datname, temp_files AS "Temporary files", pg_size_pretty(temp_bytes) AS "Size of temporary files" FROM pg_stat_database;
datname | Temporary files | Size of temporary files
---------------+-----------------+-------------------------
cloudsqladmin | 0 | 0 bytes
template0 | 0 | 0 bytes
postgres | 0 | 0 bytes
template1 | 0 | 0 bytes
first | 33621 | 722 GB
second | 9 | 3399 MB
third | 293313 | 153 GB
(7 rows)
According to the results of the query above we have ~1TB of potentially useless files. There are couple of questions:
How to identify temp files not used by any running queries?
How to remove them having that postgres is managed by Google Cloud SQL?
As per the PostgreSQL documentation, the field temp_bytes is defined as:
Total amount of data written to temporary files by queries in this
database. All temporary files are counted, regardless of why the
temporary file was created, and regardless of the log_temp_files
setting.
Meaning, that the number is the sum of the temporary file sizes since the creation of the database (or since last pg_stat_reset()), and not the current temp file usage.
The current usage could be determined using the 'file functions' in non-cloud database instance, but in Cloud SQL a normal user can not execute select pg_ls_dir('base/pgsql_temp') as this is reserved only to superusers.
As you said, Cloud SQL is a managed service, therefore at the moment, there is no way to see the current temp file usage.
One thing that will definitely clear the number you see is pg_stat_reset(), though as said before, it is not about current temp file usage, but a historical total;
One thing guaranteed to clean out temp files is restarting of the database instance, as part of the start process is wiping the base/pgsql_temp directory.

Start OrientDB without user input

I'm attempting to start OrientDB in distributed mode on AWS.
I have an auto scaling group that creates new nodes as needed. When the nodes are created, they start with a default config without a node name. The idea is that the node name is generated randomly.
My problem is that the server starts up and ask for user input.
+---------------------------------------------------------------+
| WARNING: FIRST DISTRIBUTED RUN CONFIGURATION |
+---------------------------------------------------------------+
| This is the first time that the server is running as |
| distributed. Please type the name you want to assign to the |
| current server node. |
| |
| To avoid this message set the environment variable or JVM |
| setting ORIENTDB_NODE_NAME to the server node name to use. |
+---------------------------------------------------------------+
Node name [BLANK=auto generate it]:
I don't want to set the node name because I need a random name and the server never starts because it's waiting for user input.
Is there a parameter I can pass to dserver.sh that will pass this check and generate a random node name?
You could create a random string to pass to OrientDB as node name with the ORIENTDB_NODE_NAME variable. Example:
ORIENTDB_NODE_NAME=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
For more information about this, look at: https://gist.github.com/earthgecko/3089509