need to output BitLocker status to txt file - powershell

I have a simple PowerShell script to check the status of BitLocker drive encryption on a computer on the network. I'd like for the script to determine the status of multiple computers in a text file.
Here's my basic script so far that Nathan Rice had helped with:
$TextFilePath = Read-Host "What is the path to the text file?"
If (Test-Path $TextFilePath) {
$ComputersArray = Get-Content $TextFilePath
ForEach ($Computer in $ComputersArray) {
If (Test-Connection $Computer -Count 1) {
$ComputerStatus = manage-bde -status -cn "$Computer"
Write-Host($ComputerStatus)
} Else {
Write-Host("$Computer appears to be offline.")
}
}
} Else {
Write-Error "The text file was not found, check the path."
}
I modified the code but it only writes one result to the text file, meaning if I have 5 computers in the list, it writes only the results for the first computer:
$TextFilePath = Read-Host "What is the path to the text file?"
If (Test-Path $TextFilePath){
$ComputersArray = Get-Content $TextFilePath
ForEach ($Computer in $ComputersArray) {
If (Test-Connection $Computer -Count 1) {
$ComputerStatus = manage-bde -status -cn "$Computer" |
Out-File -filepath "c:\users\enduser\Bitlocker-Status.txt"
} Else {
Write-Host("$Computer appears to be offline.")
}
}
} Else {
Write-Error "The text file was not found, check the path."
}
I'd like it to write the results for each device to the list.

Create a collection of results. After the loop, write the collection to a file.
$TextFilePath = Read-Host "What is the path to the text file?"
If (Test-Path $TextFilePath){
$ComputersArray = Get-Content $TextFilePath
$ComputerStatusCol = #()
ForEach ($Computer in $ComputersArray) {
If (Test-Connection $Computer -Count 1){
$ComputerStatus = manage-bde -status -cn "$Computer"
$ComputerStatusCol += $ComputerStatus
} Else {
Write-Host("$Computer appears to be offline.")
}
}
$ComputerStatusCol | Out-File -filepath "c:\users\enduser\Bitlocker-Status.txt"
} Else {
Write-Error "The text file was not found, check the path."
}

You need to add the parameter -Append to the Out-File, so that your output is appended to the existing content instead of replacing it:
$ComputerStatus = manage-bde -status -cn "$Computer" |
Out-File -filepath "c:\users\enduser\Bitlocker-Status.txt" -append -force

Easy batch file for admins who want a nice easy file to look through. Just set this up at one of my clients AD Networks, worked like a charm:
Setup a .cdm file, dump it into the netlogon folder
script:
echo Computer:%ComputerName% with username:%username% - Bitlocker check of drive C: >> "\server\share\folder\BitlockerCheck.log"manage-bde -status c: >> "\server\share\folder\BitlockerCheck\BitlockerCheck.log"
Make sure everyone has access to share path (domain users)Edit Group Policy for the container you want it to run in (default domain policy should never be touched, if you want everyone, make a new policy at the top and name it Bitcloker status check).
Go to User Configuration - Policies - Windows Settings - Scripts Right-click Logon, properties, Add - browse to \dcname\netlogon\filename.cmdclick OK, after about 15 minutes (without a forced gpupdate) the file will start populating as users logon/logoff.
On Non-BitLocker computers, it will show the computer name and user with no info.May be cumbersome on very large networks, but you could break out Gp script by OU and separate files as most large companies don't have everyone in one container.

Related

Powershell output formatting?

I have a script that scans for a specific folder in users AppData folder. If it finds the folder, it then returns the path to a txt file. So we can see the computer name and username where it was found.
I would like to be able to format the what is actually written to the text file, so it removes everything from the path except the Computer and User names.
Script:
foreach($computer in $computers){
$BetterNet = "\\$computer\c$\users\*\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm"
Get-ChildItem $BetterNet | ForEach-Object {
$count++
$betternetCount++
write-host BetterNet found on: $computer
Add-Content "\\SERVERNAME\PowershellScans\$date\$time\BetterNet.txt" $_`n
write-host
}
}
The text files contain information like this
\\computer-11-1004S10\c$\users\turtle\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm
\\computer-1004-24S\c$\users\camel\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm
\\computer-1004-23S\c$\users\rabbit\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm
If you have each line in a form of the string $string_containing_path then it is easy to split using split method and then add index(1) and (4) that you need:
$afterSplit = $string_containing_path.Split('\')
$stringThatYouNeed = $afterSplit[1] + " " + $afterSplit[4]
You can also use simple script that will fix your current logs:
$path_in = "C:\temp\list.txt"
$path_out= "C:\temp\output.txt"
$reader = [System.IO.File]::OpenText($path_in)
try {
while($true){
$line = $reader.ReadLine()
if ($line -eq $null) { break }
$line_after_split_method = $line.Split('\')
$stringToOutput = $line_after_split_method[1] + " " + $line_after_split_method[4] + "`r`n"
add-content $path_out $stringToOutput
}
add-content $path_out "End"
}
finally {
$reader.Close()
}
If you split your loop into two foreach loops, one for computer and user directory it would be easier to output the name of the user directory.
$output = foreach($computer in $computers){
$UserDirectories = Get-ChildItem "\\$computer\c$\users\" -Directory
foreach ($Directory in $UserDirectories) {
$BetterNet = Get-ChildItem (Join-Path $Directory.fullname "\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm")
Add-Content "\\SERVERNAME\PowershellScans\$date\$time\BetterNet.txt" "$computer $($Directory.name)`r`n"
write-host BetterNet found on: $computer
$BetterNet
}
}
$output.count

writing output file as .txt or .csv to script containing multiple conditions

I have written a script which checks a service status, tests two paths and also tests a registry value. Currently I am getting output on the power shell console (that could be because I am using write-output command).
Is there any way to write the single one page output to a file?
I am struggling to find a way to out-file entire output to a file.
Below is the script.
$testpath = Test-Path "C:\test"
$testpath2 = test-path "C:\test"
$mcshieldk = Get-Service -Name mcshield | select Name
$internet = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\internet explorer").MkEnabled $hostname = hostname Write-Host "hostname of comuter is" $hostname if (Test-Path $Machinetype)
{}
else { Write-Host "internet is" $internet }
if ($testpath -eq $true -and $testpath2 -eq $true)
{ Write-Host "test and test1 folder exists" -ForegroundColor Green }
else{ Write-Host "folder does not exists" -ForegroundColor Red } if($mcshield.Name -eq "mcshield") { Write-Host "mcshield service exists" }
else { Write-Host "mcshield does not exists" }
Below is the console output
hostname of comuter is Server1
internet is Yes
test and test1 folder exists
mcshield does not exists
Swap out your Write-Host cmdlets or add in another line with the following:
"Your output text $YourVariable" | Out-File -FilePath "C:\Log.txt" -Append -Encoding utf8
This will append a string to the end of the log file C:\Log.txt. Note, missing the -Append parameter will cause the file to be overwritten.
You can also use the follow to give the same affect:
"Your output text $YourVariable" >> "C:\Log.txt"
But be carefully not to mix the two methods as you might get encoding errors in the text file. If you wish to overwrite the file with the second method use > instead of >>.

Select option from Array

I am working on a side project and to make it easier for managment since almost all of out server names are 15 charactors long I started to look for an RDP managment option but none that I liked; so I started to write one and I am down to only one issue, what do I do to manage if the user types not enough for a search so two servers will match the Query. I think I will have to put it in an array and then let them select the server they meant. Here is what I have so far
function Connect-RDP
{
param (
[Parameter(Mandatory = $true)]
$ComputerName,
[System.Management.Automation.Credential()]
$Credential
)
# take each computername and process it individually
$ComputerName | ForEach-Object{
Try
{
$Computer = $_
$ConnectionDNS = Get-ADComputer -server "DomainController:1234" -ldapfilter "(name=$computer)" -ErrorAction Stop | Select-Object -ExpandProperty DNSHostName
$ConnectionSearchDNS = Get-ADComputer -server "DomainController:1234" -ldapfilter "(name=*$computer*)" | Select -Exp DNSHostName
Write-host $ConnectionDNS
Write-host $ConnectionSearchDNS
if ($ConnectionDNS){
#mstsc.exe /v ($ConnectionDNS) /f
}Else{
#mstsc.exe /v ($ConnectionSearchDNS) /f
}
}
catch
{
Write-Host "Could not locate computer '$Computer' in AD." -ForegroundColor Red
}
}
}
Basically I am looking for a way to manage if a user types server1
that it will ask does he want to connect to Server10 or Server11 since both of them match the filter.
Another option for presenting choices to the user is Out-GridView, with the -OutPutMode switch.
Borrowing from Matt's example:
$selection = Get-ChildItem C:\temp -Directory
If($selection.Count -gt 1){
$IDX = 0
$(foreach ($item in $selection){
$item | select #{l='IDX';e={$IDX}},Name
$IDX++}) |
Out-GridView -Title 'Select one or more folders to use' -OutputMode Multiple |
foreach { $selection[$_.IDX] }
}
else {$Selection}
This example allows for selection of multiple folders, but can you can limit them to a single folder by simply switching -OutPutMode to Single
I'm sure what mjolinor has it great. I just wanted to show another approach using PromptForChoice. In the following example we take the results from Get-ChildItem and if there is more than one we build a collection of choices. The user would select one and then that object would be passed to the next step.
$selection = Get-ChildItem C:\temp -Directory
If($selection.Count -gt 1){
$title = "Folder Selection"
$message = "Which folder would you like to use?"
# Build the choices menu
$choices = #()
For($index = 0; $index -lt $selection.Count; $index++){
$choices += New-Object System.Management.Automation.Host.ChoiceDescription ($selection[$index]).Name, ($selection[$index]).FullName
}
$options = [System.Management.Automation.Host.ChoiceDescription[]]$choices
$result = $host.ui.PromptForChoice($title, $message, $options, 0)
$selection = $selection[$result]
}
$selection
-Directory requires PowerShell v3 but you are using 4 so you would be good.
In ISE it would look like this:
In standard console you would see something like this
As of now you would have to type the whole folder name to select the choice in the prompt. It is hard to get a unique value across multiple choices for the shortcut also called the accelerator key. Think of it as a way to be sure they make the correct choice!

Powershell write-host not working when logged in as another admin

I have the below powershell script that I call via a command prompt outputting any text to >> .log file. What it does is it creates 2 OU's based on variables from an input file, checks to see if those OU's got created and finally outputs to a .log file (this is entered in the command prompt). It works as expected when executing the code as a domain admin on the abc.acme.ldt.com domain; it creares the OU's and outputs the text to .log file as expected.
But I'm experiencing a weird problem when running it as a forest admin acme.ldt.com user (with local domain admin privileges on that child domain ABC); It's able to create the OU's successfully but for whatever the reason it does not output the text file to the .log file. If I check with a [ADSI]::Exists("full-manual-path") I get a TRUE in response, so the script does create the OU's but I just cant get the text to appear in the .log file as I do when executing as a domain admin on the ABC domain.
Import-Csv ".\source\input.csv" | ForEach {
If ($_.FQDN -eq $(gwmi win32_computersystem).domain) { $OU_Name1 = $_.'OU Name1' }
If ($_.FQDN -eq $(gwmi win32_computersystem).domain) { $OU_Name2 = $_.'OU Name2' }
If ($_.FQDN -eq $(gwmi win32_computersystem).domain) { $OU_Name3 = $_.'OU Name3' }
If ($_.FQDN -eq $(gwmi win32_computersystem).domain) { $Path1 = $_.'OU Path1' }
If ($_.FQDN -eq $(gwmi win32_computersystem).domain) { $Path2 = $_.'OU Path2' }
If ($_.FQDN -eq $(gwmi win32_computersystem).domain) { $Full_windows7_OU_Path2 = $_.'Full Windows 7 OU path2' }
}
New-ADorganizationalUnit -Name $OU_Name1 -Path "$Path1"
Start-Sleep -s 10
New-ADorganizationalUnit -Name $OU_Name2 -Path "$Path2"
New-ADorganizationalUnit -Name $OU_Name3 -Path "$Path2"
if ([ADSI]::Exists("LDAP://$Full_windows7_OU_Path2"))
{
Write-Host "# Checking Logs to Confirm the OU Structure For Win7 Has been created #"
} Else {
Exit
}
Sometimes the simplest things let us doubt ourselves..
As I said in the comment:
Check if that user has write permissions on the share with: "test" | Out-File $location
You're welcome :)

file location different on computers and space issues

I have the below code and currently checks computer for version info and service status.
The problem I have is that servers have the located .exe in different places:
C:\program files\snare\snarecore.exe
C:\program files (x86)\snare\snarecore.exe
D:\apps\snare\snarecore.exe
How do I get the script below to run the right version? I think I can use the path that the service is checking? I am doing this all remotly and have rights to the server and works fine - but I am having to possiblt make three (or more!) scripts just based on all three locations of where the executable is!
Also, for the ones that have a space in the name (../program file..) where do I put the quotes so that powershell can read the whole line and not error out due to the space in the name?
CODE:
clear
$ErrorActionPreference = "silentlycontinue"
$Logfile = "C:\temp\output_cdrive.log"
Function LogWrite
{
param([string]$logstring)
Add-Content $Logfile -Value $logstring
}
$computer = Get-Content -Path c:\temp\servers2.txt
foreach ($computer1 in $computer){
$Service = Get-WmiObject Win32_Service -Filter "Name = 'Snare'" -ComputerName $computer1
if (test-connection $computer1 -quiet)
{
$version = (Get-Command ""\\$computer1\c$\Program Files (x86)\Snare\SnareCore.exe"").FileVersionInfo.FileVersion
if($Service.state -eq 'Running')
{
LogWrite "$computer1 STARTED $version"
}
else
{
LogWrite "$computer1 STOPPED $version"
}
}
else
{
LogWrite "$computer1 is down" -foregroundcolor RED
}
}
Thanks,
you can check the pathname property of you service to get the exe location :
PS>(Get-WmiObject Win32_Service -Filter "name='spooler'").pathname
C:\Windows\System32\spoolsv.exe
The obvious solution is to use a path variable, assign that variable each of the three different paths in turn, and write your actual checks as a function using that variable.
You can escape the double quotes using the backtick:
"`"\\$computer1\c$\Program Files (x86)\Snare\SnareCore.exe`""