Powershell script to disable bit locker protection - powershell-4.0

Am a new bie to Powershell and knew less comlets.
As per my requirement, I need to disable the bit locker protection no a drive.
I have a script to get the status of bit locker protection is On or Off.
$x = Get-WMIObject -Namespace "root/CIMV2/Security/MicrosoftVolumeEncryption" -query "SELECT * FROM Win32_EncryptableVolume WHERE DriveLetter='C:'";
$y = $x.GetProtectionStatus().ProtectionStatus
$y
Which displays the protection status as 0 or 1.
Please help me with script to disable the protection for bit locker drive.

Use the disable-bitlocker command:
PS C:> Disable-BitLocker -MountPoint "D:"
Or whatever drive you need to disable. Why do you need to do this in the first place? There is a difference between disable and recover.

There are as Charles pointed out proper cmdlets for this these days, instead of using the old-school WMI objects.
Get a list of all available commandlets for bitlocker
Get-Command *Bitlocker*
To disable on one of the drives, use the cmdlet:
Disable-Bitlocker
If you're stuck with an older version of Powershell/Windows, you can go for the approach of writing the value to the WMI object.

Related

What can I do about "WMIC is deprecated"?

I've been relying on these two commands:
wmic memorychip get capacity // Outputs how much RAM there is (in a convoluted manner).
wmic diskdrive get Status,Model // Checks whether the HDDs/SSDs on the system are (supposedly) still "OK" and working.
Today, I casually typed "wmic" to see if I could get JSON output to the above commands. The first thing it printed, in red text, was this:
WMIC is deprecated.
I was pretty shocked by this. It's deprecated? Alright... Then I definitely should not be relying on it. What are the "modern alternatives" for those two commands, then? Do they even exist? Why do they just tell us that it's "deprecated" with zero further information?
As mentioned in comments, WMIC is utility that acts as interface to communication with WMI. It's not WMI itself that is being deprecated, but "just" the interface. Since Microsoft is pushing PowerShell, I believe official successor wmic would be PowerShell commandlet Get-WmiObject. How to use this can be found on Microsoft documentation: LINK
[UPDATED] As correctly pointed out within comment, commandlet Get-WmiObject may eventually sunset one day as well and thus its use may not be encouraged to have scripts future proof. Best method to stick with would be Get-CimInstance, which has pretty much the same syntax as Get-WmiObject. See Microsoft documentation: LINK
For your particular case PowerShell alternative would be the following:
wmic memorychip get capacity
Get-CimInstance -ClassName Win32_PhysicalMemory | Select-Object capacity
wmic diskdrive get Status,Model
Get-CimInstance -ClassName Win32_diskdrive | Select-Object status, model
Commands in wmic are usually derived from WMI class names, but it's not really a rule of thumb. With PowerShell you are accessing WMI by its real class name instead, so you may need to seek for other classes if needed.
As mentioned in comment by Bacon Bits. WMIC aliases to real WMI classes can be obtained by command:
wmic.exe alias list brief
Undisputed advantage to PowerShell over wmic is that output is an object and you can easily continue working with the output, while wmic returns a string only that you eventually need to parse for example if used inside scripts and that brings another benefit of e.g. output formatting - you can easily reformat any output for example to as you mentioned JSON, just pass your command through another pipe into commandlet ConvertTo-Json and you will have your expected output.
Example:
Get-CimInstance -ClassName Win32_diskdrive | select status, model | ConvertTo-JSON
Output:
{
"status": "OK",
"model": "SAMSUNG MZNTY256HDHP-000L7"
}
Hope this helps
[UPDATE 2.2.2022]
Since this is the first link on Google for this topic that pops out, here's small update:
Microsoft officially informed about wmic being deprecated in their WMIC documentation
Microsoft page quotes:
The WMI command-line (WMIC) utility is deprecated as of Windows 10, version 21H1, and as of the 21H1 semi-annual channel release of Windows Server. This utility is superseded by Windows PowerShell for WMI. This deprecation applies only to the WMI command-line (WMIC) utility; Windows Management Instrumentation (WMI) itself is not affected.
For the sake of future proof scripts, I would still stick with industrial CIM standard using PowerShell

Windows script to enable TPM

I am looking to write a script that will enable a TPM chip and BitLocker in Windows, with VBScript. I am new to VBScript and Windows scripting in general.
One part that I seem to be hitting a snag on is having my script start up again after a reboot.
For example, to enable the TPM chip a reboot is required to turn on the chip, and then a second reboot is required to take ownership of the TPM chip. A third reboot would be required to enable BitLocker.
How do I have the script start up again after each reboot to move to the next step? And is VBscript the best choice to accomplish this task?
Something like this should work:
rem Make sure you applied the appropriate policies before activating!
manage-bde -tpm -TurnOn
manage-bde -tpm -TakeOwnership PASSWORD
manage-bde -on C: -RecoveryPassword -SkipHardwareTest
The TPM must be enabled in the BIOS first, though.
Microsoft already provides a VBScript for enabling BitLocker. You can learn more about it here:
Enabling BitLocker by using a WMI script
And the script itself is available from here:
BitLocker Deployment Sample Resources

Speed Up PowerShell Scripts in V2?

I'm running a number of scripts using PowerShell V2, and I have noticed a long pause when the console window first loads. What can I do to improve the performance of my scripts?
Thanks, MagicAndi
Other than minimize what you put in your various profile scripts (shown below) there isn't much you can do:
C:\PS> $profile | fl * -force
AllUsersAllHosts : C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1
AllUsersCurrentHost : C:\Windows\System32\WindowsPowerShell\v1.0\Microsoft.PowerShell_profile.ps1
CurrentUserAllHosts : C:\Users\hillr\Documents\WindowsPowerShell\profile.ps1
CurrentUserCurrentHost : C:\Users\hillr\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
One way to check to see if profile scripts are causing the lag is to start powershell using the -noprofile option. If the startup time is different it would be due to your profile scripts. You can use a .NET stopwatch like so:
function TimeThis([scriptblock]$scriptblock, $msg)
{
if (!$stopWatch)
{
$script:stopWatch = new-object System.Diagnostics.StopWatch
}
$stopWatch.Reset()
$stopWatch.Start()
. $scriptblock
$stopWatch.Stop()
if ($msg -eq $null) { $msg = "$scriptblock" }
"Execution time: $($stopWatch.ElapsedMilliseconds) mS for $msg"
}
. TimeThis {Import-Module $Module -args ~\Pscx.UserPreferences.ps1}
While you could use Measure-Command, it doesn't show what is executed and you get no command output (only time in a very verbose fashion).
There used to be an issue in earlier CTPs where the installer wouldn't ngen the PowerShell assemblies and that could cause noticeable load time delays. However I'm pretty sure that has been fixed as of the final 2.0 install (and certainly with PowerShell built into Windows 7 and Windows Server 2008 R2). If the follow dir and its contents exist, you should be ngen'd:
dir 'C:\Windows\assembly\NativeImages_v2.0.50727_32\Microsoft.PowerShel#' -r
Tracking down a performance issue like this can be tricky, but there are a few things you can do to improve / fix things.
First off, starting PowerShell cold versus warm. At least on my workstation, the first time I run PS in the morning, it takes a bit longer to launch than subsequent times. Is there a way you can keep it warm to minimize the load times?
Second, use a tool like Process Monitor from the fine folks working for Windows Sysinternals. Set it to monitor the powershell.exe process and see what it is doing that is taking so long. For me, I have a number of mapped network drives and shared scripts that get sourced from the network. In my testing, I measured about a two second delay in starting per remote script I was loading.
PowerShell does need to load a bunch of resources from disk into memory, so it should go without saying that having your I/O system perform optimally will help as well. Defrag, make sure you have ample free RAM, etc. It even queries quite a bit from the registry so you may want to ensure your registry is completely defragged - though that is quite a long shot.
It may be completely unrelated but I have once had a massive pause during powershell startup.
It was somehow related to the fact that my laptop was in a domain, I then hibernated it and started it again when the laptop was not in the domain anymore. I looked at the startup with dottrace and could only see that somewhere in the initialization of Providers the code got stuck.
Restarting the machine helped in this case. Also it doesn't always happen (in fact, only once so far).
use inline C# speedup x100 max
Add-Type -Language CSharpVersion3 #"
"#
Add-Type #"
"#
if may not use -TypeDefinition #"
use 32bit powershell
speedup x1,5
ps-run.cmd :
SET PS32=%windir%\SysWOW64\WindowsPowerShell\v1.0\powershell
%PS32% .\%*

WMI "installed" query different from add/remove programs list?

Trying to use WMI to obtain a list of installed programs for Windows XP. Using wmic, I tried:
wmic /output:c:\ProgramList.txt product get name,version
and I get a listing of many of the installed programs, but after scrubbing this list against what "Add/Remove Programs" displays, I see many more programs listed in the GUI of Add/Remove Programs than with the WMI query. Is there another WMI query I need to use to get the rest of the programs installed? Or is there some other place I need to look for the rest?
Also, there are two installed programs that are listed in the WMI query that aren't in Add/Remove programs. Any idea why?
I believe your syntax is using the Win32_Product Class in WMI. One cause is that this class only displays products installed using Windows Installer (See Here). The Uninstall Registry Key is your best bet.
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall
UPDATE FOR COMMENTS:
The Uninstall Registry Key is the standard place to list what is installed and what isn't installed. It is the location that the Add/Remove Programs list will use to populate the list of applications. I'm sure that there are applications that don't list themselves in this location. In that case you'd have to resort to another cruder method such as searching the Program Files directory or looking in the Start Menu Programs List. Both of those ways are definitely not ideal.
In my opinion, looking at the registry key is the best method.
All that Add/Remove Programs is really doing is reading this Registry key:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall
Besides the most commonly known registry key for installed programs:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall
wmic command and the add/remove programs also query another registry key:
HKEY_CLASSES_ROOT\Installer\Products
Software name shown in the list is read from the Value of a Data entry within this key called: ProductName
Removing the registry key for a certain product from both of the above locations will keep it from showing in the add/remove programs list. This is not a method to uninstall programs, it will just remove the entry from what's known to windows as installed software.
Since, by using this method you would lose the chance of using the Remove button from the add/remove list to cleanly remove the software from your system; it's recommended to export registry keys to a file before you delete them. In future, if you decided to bring that item back to the list, you would simply run the registry file you stored.
I have been using Inno Setup for an installer. I'm using 64-bit Windows 7 only. I'm finding that registry entries are being written to
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
I haven't yet figured out how to get this list to be reported by WMI (although the program is listed as installed in Programs and Features). If I figure it out, I'll try to remember to report back here.
UPDATE:
Entries for 32-bit programs installed on a 64-bit machine go in that registry location. There's more written here:
http://mdb-blog.blogspot.com/2010/09/c-check-if-programapplication-is.html
See my comment that describes 32-bit vs 64-bit behavior in that same post here:
http://mdb-blog.blogspot.com/2010/09/c-check-if-programapplication-is.html?showComment=1300402090679#c861009270784046894
Unfortunately, there doesn't seem to be a way to get WMI to list all programs from the add/remove programs list (aka Programs and Features in Windows 7, not sure about Vista). My current code has dropped WMI in favor of using the registry. The code itself to interrogate the registry is even easier than using WMI. Sample code is in the above link.
Not the best, but whether it is practical method:
Use HijackThis. (Old version: HijackThis)
Run hijack this, click the "Open the Misc Tools section" button
click "Open Uninstall Manager"
click save list (*.txt), yes to the prompts, notepad will open with your add/remove programs list.
Source
You can get it in one line with powershell and batch file :
#echo off
Powershell /command "Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Format-List"
Pause
Installed products consist of installed software elements and features so it's worth checking wmic alias's for PRODUCT as well as checking SOFTWAREELEMENT and SOFTWAREFEATURE:
wmic product get name,version
wmic softwareelement get name,version
wmic softwarefeature get name,version
You can use the script from http://technet.microsoft.com/en-us/library/ee692772.aspx#EBAA to access the registry and list applications using WMI.
Hope this helps somebody: I've been using the registry-based enumeration in my scripts (as suggested by some of the answers above), but have found that it does not properly enumerate 64-bit software when run on Windows 10 x64 via SCCM (which uses a 32-bit client). Found something like this to be the most straightforward solution in my particular case:
Function Get-Programs($Bits) {
$Result = #()
$Output = (reg query HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall /reg:$Bits /s)
Foreach ($Line in $Output) {
If ($Line -match '^\s+DisplayName\s+REG_SZ\s+(.+?)$') {
$Result += New-Object PSObject -Property #{
DisplayName = $matches[1];
Bits = "$($Bits)-bit";
}
}
}
$Result
}
$Software = Get-Programs 32
$Software += Get-Programs 64
Realize this is a little too Perl-ish in a bad way, but all other alternatives I've seen involved insanity with wrapper scripts and similar clever-clever solutions, and this seems a little more human.
P.S. Trying really hard to refrain from dumping a ton of salt on Microsoft here for making an absolutely trivial thing next to impossible. I.e., enumerating all MS Office versions in use on a network is a task to make a grown man weep.
With time having moved on quite a bit since this question was asked...
There's a WMI class available these days for the Uninstall entries in the registry. This is much quicker to reference than Win32_Product, which I think also runs verification on the list and can take a while to enumerate. The below Powershell code (possibly requires Powershell 3 or later) will list all entries (The Out-Gridview part is just for a pretty display).
Get-CimInstance Win32Reg_AddRemovePrograms | Out-gridview
Add/Remove Programs also has to look into this registry key to find installations for the current user:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Uninstall
Applications like Google Chrome, Dropbox, or shortcuts installed through JavaWS (web start) JNLPs can be found only here.
In order to build a more-or-less reliable list of applications that appear in the "Programs and Feautres" in the Control Panel, you have to consider that not all applications were installed using MSI. WMI only provides the ones installed with MSI.
Here is a short summary of what I've found out:
MSI applications always have a Product Code (GUID) subkey under HKLM\...\Uninstall and/or under HKLM\...\Installer\UserData\S-1-5-18\Products. In addition, they may have a key that looks like HKLM\...\Uninstall\NotAGuid.
Non-MSI applications do not have a product code, and therefore have keys like HKLM\...\Uninstall\NotAGuid or HKCU\...\Uninstall\NotAGuid.
I adapted the MS-Technet VBScript for my needs. It dumps Wow6432Node as well as standard entries into "programms.txt"
Use it at your own risk, no warranty!
Save as dump.vbs
From command line type: wscript dump.vbs
Const HKLM = &H80000002
Set objReg = GetObject("winmgmts://" & "." & "/root/default:StdRegProv")
Set objFSO = CreateObject("Scripting.FileSystemObject")
outFile="programms.txt"
Set objFile = objFSO.CreateTextFile(outFile,True)
writeList "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\", objReg, objFile
writeList "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\", objReg, objFile
objFile.Close
Function writeList(strBaseKey, objReg, objFile)
objReg.EnumKey HKLM, strBaseKey, arrSubKeys
For Each strSubKey In arrSubKeys
intRet = objReg.GetStringValue(HKLM, strBaseKey & strSubKey, "DisplayName", strValue)
If intRet <> 0 Then
intRet = objReg.GetStringValue(HKLM, strBaseKey & strSubKey, "QuietDisplayName", strValue)
End If
objReg.GetStringValue HKLM, strBaseKey & strSubKey, "DisplayVersion", version
objReg.GetStringValue HKLM, strBaseKey & strSubKey, "InstallDate", insDate
If (strValue <> "") and (intRet = 0) Then
objFile.Write strValue & "," & version & "," & insDate & vbCrLf
End If
Next
End Function
I had the same issue with the WMIC command only showing a subset of all installed programs. I needed a command that would output a CSV file of all the installed programs in Windows 10 and I wanted to make it easy for colleagues to run. The following Powershell command seems to work well, running much quicker than the WMIC command; it will generate a CSV in the user's Documents folder called AppsInstalled.csv with programs sorted by name, and with empty lines removed (numerous blank lines were returned in my tests for some reason?).
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate| Where-Object DisplayName -ne $null | Sort-Object -Property DisplayName | Export-Csv "$($env:USERPROFILE)\Documents\AppsInstalled.csv" -NoTypeInformation

Detecting installed programs via registry

I need to develop a process that will detect if the users computer has certain programs installed and if so, what version. I believe I will need a list with the registry location and keys to look for and feed it to the program which is not a problem. Is there a better way to accomplish this?
My first thought was to check in the registry in the uninstallation entries but it seems one of the apps I wish to detect does not have one. What is the standard location for all registry using applications to make an entry in?
On 64-bit systems the x64 key is:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
Most programs are listed there. Look at the keys:
DisplayName
DisplayVersion
Note that the last is not always set!
On 64-bit systems the x86 key (usually with more entries) is:
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
User-specific settings should be written to HKCU\Software, machine-specific settings to HKLM\Software. Under these keys, structure [software vendor name]\[application name] (e.g. HKLM\Software\Microsoft\Internet Explorer) may be the most common, but that's just a convention, not a law of nature.
Many (most?) applications also add their uninstall entries to HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\[app name], but again, not all applications do this.
These are the most important keys; however, contents of the registry do not have to represent the installed software exactly - maybe the application was installed once, but then was manually deleted, or maybe the uninstaller didn't remove all traces of it. If you want to be sure, check the filesystem to see if the application still exists where its registry entries say it is.
Edit:
If you're a member of the group Administrators, you can check the HKEY_USERS hive - each user's HKCU actually resides there (you'll need to know the user SID, or go through all of them).
Note: As #Brian Ensink says, "installed" is a bit of a vague concept - are we trying to find what the user could run? Some software doesn't even write to the Registry at all: search for "portable apps" to see apps that have been specifically modified to run directly from media (CD/USB) and not to leave any traces on the computer. We may also have to scan the disks, and network disks, and anything the user downloads, and world-accessible Windows shares in the Internet (yes, such things exist legitimately - \\live.sysinternals.com\tools comes to mind). In this direction, there's no real limit of what the user can run, unless prevented by system policies.
You could use MSI API to enumerate everything installed by Windows Installer but that won't list all the software available on a machine. Without knowing more about what you need I think the concept of "installed" is a little vague. There are many ways to deploy software to a system ranging from big complicated installers to ZIP files and everything in between.
An application does not need to have any registry entry. In fact, many applications do not need to be installed at all. U3 USB sticks are a good example; the programs on them just run from the file system.
As noted, most good applications can be found via their uninstall registry key though. This is actually a pair of keys, per-user and per-machine (HKCU/HKLM - Piskvor mentioned only the HKLM one). It does not (always) give you the install directory, though.
If it's in HKCU, then you have to realise that HKEY_CURRENT_USER really means "Current User". Other users have their own HKCU entries, and their own installed software. You can't find that. Reading every HKEY_USERS hive is a disaster on corporate networks with roaming profiles. You really don't want to fetch 1000 accounts from your remote [US|China|Europe] office.
Even if an application is installed, and you know where, it may not have the same "version" notion you have. The best source is the "version" resource in the executables. That's indeed a plural, so you have to find all of them, extract version resources from all and in case of a conflict decid on something reasonable.
So - good luck. There are dozes of ways to fail.
You can use a PowerShell script to look at registers and get the installed program details. The script bellow will generate a file with the complete list of installed programs. Save it with ".ps" extension and double click the file.
#
# Generates a full list of installed programs.
#
# Temporary auxiliar file.
$tmpFile = "tmp.txt"
# File that will hold the programs list.
$fileName = "programas-instalados.txt"
# Columns separator.
$separator = ","
# Delete previous files.
Remove-Item $tmpFile
Remove-Item $fileName
# Creates the temporary file.
Create-Item $tmpFile
# Searchs register for programs - part 1
$loc = Get-ChildItem HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall
$names = $loc |foreach-object {Get-ItemProperty $_.PsPath}
foreach ($name in $names)
{
IF(-Not [string]::IsNullOrEmpty($name.DisplayName)) {
$line = $name.DisplayName+$separator+$name.DisplayVersion+$separator+$name.InstallDate
Write-Host $line
Add-Content $tmpFile "$line`n"
}
}
# Searchs register for programs - part 2
$loc = Get-ChildItem HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
$names = $loc |foreach-object {Get-ItemProperty $_.PsPath}
foreach ($name in $names)
{
IF(-Not [string]::IsNullOrEmpty($name.DisplayName)) {
$line = $name.DisplayName+$separator+$name.DisplayVersion+$separator+$name.InstallDate
Write-Host $line
Add-Content $tmpFile "$line`n"
}
}
# Sorts the result, removes duplicate lines and
# generates the final file.
gc $tmpFile | sort | get-unique > $filename
Seems like looking for something specific to the installed program would work better, but HKCU\Software and HKLM\Software are the spots to look.
In addition to all the registry keys mentioned above, you may also have to look at HKEY_CURRENT_USER\Software\Microsoft\Installer\Products for programs installed just for the current user.
Win32_Product never shows everything, only software installed via an MSI installer (as far as I can tell.)
There are lots of software packages that get installed via other installers that don't show up in there. another way is needed.
HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Compatibility Assistant\Persisted

Resources