WindowsServer 2003 cmd check installed roles - powershell

I am creating a large batch script to check installed windows features (components) on a Windows 2003 server. I can not seem to figure out how to query server roles and display all sub-features of the role within the cmd shell. This is easy to do in Windows Server 2008 by simply using servermanager.exe or WMI, but I cannot figure out what program or cmd to use in Windows 2003. Windows Server 2003 has power shell installed, but it just seems like a glorified cmd shell in this Windows OS version. Does anyone know of a similar utility or cmd that can be used specifically on a Windows 2003 box? Thanks for your time.

You can try this function
function Get-InstalledComponents($computer = '.') {
$components_installed = #();
$reg_paths = #('SOFTWARE\Microsoft\Windows\CurrentVersion'`
+ '\Setup\Oc Manager\Subcomponents');
$reg_paths += #('SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion'`
+ '\Setup\Oc Manager\Subcomponents');
$hkey = 'LocalMachine';
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($hkey, $computer);
foreach ($reg_path in $reg_paths) {
$reg_key = $reg.OpenSubKey($reg_path);
if ($reg_key -eq $null) {
continue;
}
$names = $reg_key.GetValueNames();
foreach ($name in $names) {
$value = $reg_key.GetValue($name);
if ($value -gt 0) {
$components_installed += #($name);
}
}
$reg_key.close();
}
$reg.close();
if ($components_installed.count -lt 1) {
trap { ;
continue } $features = #(get-wmiobject -class 'Win32_ServerFeature' `
-computer $computer -erroraction 'Stop');
foreach ($feature in $features) {
$components_installed += #($feature.name);
}
}
return ($components_installed | sort);
}

Related

Powershell script to Stop and start windows Service using S.no

I have a listed my Windows Service Names in the Text file and I have added the code to display it by adding the S.no preceding to the Names,
Listofservices.txt contains
Print Spooler
Windows Update
Remote Desktop Services
Get-Content 'C:\Services\Listofservices.txt' | ForEach-Object { $i = 1 } { "$i.$_" ; $i++ }
Result
Print Spooler
Windows Update
Remote Desktop Services
now I would like to stop, start the services by entering only the S.no and I don't want to type the exact full name
$userinput = read-host -prompt "Enter the S.no to Stop/Start"
Stop-Service -Name "$userinput" -Force -Confirm
say for example if i enter the number 1 the Print Spooler service will be stopped
Here is one way you could do it following the code you already have, but as stated in comments, this is much simpler to do with Out-GridView -PassThru. Also do note, for these services, the PowerShell process will most likely require to be elevated.
$file = Get-Content path\to\file.txt
$file | ForEach-Object { $i = 1 } { "$i.$_" ; $i++ }
$userinput = Read-Host "Enter the S.no to Stop/Start"
try {
$choice = $file[-1 + $userinput]
if(-not $choice) {
throw 'Invalid selection..'
}
$service = Get-Service $choice
if('Running' -eq $service.Status) {
$service.Stop()
"$($service.Name) has been stopped.."
return # end the script here
}
$service.Start()
"$($service.Name) has been started.."
}
catch {
if($_.Exception.InnerException.InnerException.NativeErrorCode -eq 5) {
return "Process needs to be elevated."
}
"An error ocurred: $_"
}

PowerShell function to check the health of remote disks not actually remoting

I am trying to use a script to check the health of physical disks on Lenovo computers utilizing the storcli tool. I found this and have tried to modify it to be a function and allow the input of remote computers and eventually use Get-Content to input a server list. For whatever reason it takes the computer input from -ComputerName but does not actually run the commands on the remote computer. It seems to just read the disks on the local machine and always reports back "Healthy" while I know there are bad disks on the remote machine. Also I have run the script on the machine with the bad disks and it does work and reports the disk as failed. Could anyone offer any insight into what I am missing for this to actually check the remote machines? Remoting is enabled as I can run other scripts without issue. Thank you in advance.
Function Get-DriveStatus {
[cmdletbinding()]
param(
[string[]]$computername = $env:computername,
[string]$StorCLILocation = "C:\LenovoToolkit\StorCli64.exe",
[string]$StorCliCommand = "/c0/eall/sall show j"
)
foreach ($computer in $computername) {
try {
$ExecuteStoreCLI = & $StorCliLocation $StorCliCommand | out-string
$ArrayStorCLI= ConvertFrom-Json $ExecuteStoreCLI
}catch{
$ScriptError = "StorCli Command has Failed: $($_.Exception.Message)"
exit
}
foreach($PhysicalDrive in $ArrayStorCLI.Controllers.'Response Data'.'Drive Information'){
if(($($PhysicalDrive.State) -ne "Onln") -and ($($PhysicalDrive.State -ne "GHS"))) {
$RAIDStatus += "Physical Drive $($PhysicalDrive.'DID') With Size $($PhysicalDrive.'Size') is $($PhysicalDrive.State)`n"
}
}
#If the variables are not set, We’re setting them to a “Healthy” state as our final action.
if (!$RAIDStatus) { $RAIDStatus = "Healthy" }
if (!$ScriptError) { $ScriptError = "Healthy" }
if ($ScriptError -eq "Healthy")
{
Write-Host $computer $RAIDStatus
}
else
{
Write-Host $computer "Error: ".$ScriptError
}
}#End foreach $computer
}#End function
$RAIDStatus = $null
$ScriptError = $null

How to check if Certain programs are installed and if they are display message

I'm trying to create a script that will check if Program A,B,C and D is installed. If so display message to say they are all installed else say they are not installed.
From research i have created the following script.
$ProgramList = #("A","B","C","D")
ForEach ($Program in $ProgramList){
Function Get-InstalledApps
{
$Regpath = #(
'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
)
Get-ItemProperty $Regpath | .{Process{If($_.DisplayName) { $_ } }}
}
$Result = Get-InstalledApps | Where {$_.DisplayName -like "*$Program*"}
If ($Result) {
[Windows.Forms.Messagebox]::Show("INSTALLED")
} Else {
[Windows.Forms.Messagebox]::Show("NOT INSTALLED")
}
}
My issue is when i run this i get 4 message boxes popup to say the program is installed. i'm trying to make this so it will just give a single message box. if all are installed and if one or more is not installed another message box to say the programs are not installed.
Any help is greatly Appreciated.
You're getting four pop-ups because your calling the msgbox four times (as it's within your loop). Just moving it out doesn't completely solve your problem since it's going to only look at the last one, but if you need to do it the way you are, then something like this would work:
$ProgramList = #("A","B","C","D")
$allInstalled = $true # Assume they're all installed
ForEach ($Program in $ProgramList){
Function Get-InstalledApps {
$Regpath = #(
'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
)
Get-ItemProperty $Regpath | .{Process{If($_.DisplayName) { $_ } }}
}
If(-not(Get-InstalledApps | Where {$_.DisplayName -like "*$Program*"})) {
# We know at least one isn't installed
$allInstalled = $false
}
}
If($allInstalled) {
[Windows.Forms.Messagebox]::Show("INSTALLED")
} Else {
[Windows.Forms.Messagebox]::Show("NOT INSTALLED")
}
If you're able to tweak the function a bit, you can speed it up by only pulling in the registry information once. The BEGIN section here runs just once when you call the function with multiple applications.
Function Test-InstalledApps {
Param(
[Parameter(ValueFromPipeline)]
[string[]]$appName
)
Begin {
$Regpath = #('HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*','HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*')
$allApps = Get-ItemProperty $Regpath | Select DisplayName
$allAppsInstalled = $true
}
Process {
ForEach($app in $appName) {
If(-Not($allApps | Where-Object { $_.DisplayName -like "*$app*" })) {
# We know at least one isn't installed
$allAppsInstalled = $false
}
}
}
End {
Return $allAppsInstalled
}
}
If(Test-InstalledApps #("A","B","C")) {
[Windows.Forms.Messagebox]::Show("INSTALLED")
} Else {
[Windows.Forms.Messagebox]::Show("NOT INSTALLED")
}
I think this might be a bit better approach, using Out-GridView. In my opinion this would look cleaner, I know this is not answering your question but it might suit you better:
$programList = #(
'SomeRandomProgram1'
'Microsoft Visual'
'7-Zip'
'SomeRandomProgram2'
)
$Regpath = #(
'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
)
$installedPrograms = (Get-ItemProperty $Regpath).where({$_.DisplayName})
$result = foreach($program in $programList)
{
$check = $installedPrograms.DisplayName -match $program
if($check)
{
foreach($match in $check)
{
[pscustomobject]#{
Program = $program
Status = 'Found'
Match = $match
}
}
continue
}
[pscustomobject]#{
Program = $program
Status = 'Not Found'
Match = $null
}
}
$result | Out-GridView
In my computer the OGV looks like this:
I know I'm a bit late to the game here and my answer is you might say completely different buy I did it on a quest to learn a few things and thought others might find it interesting. It produces output like this.
The interesting part is that the menu is self adjusting, within screen size limits, so you can search for more or fewer programs just by passing them in an array. The program searched directories vs the Registry so you can locate programs which are not installed (portable). By default it searches the two Windows locations but you can also pass it an array with additional search locations.
I'm sure it wouldn't take to much to modify to have it search the registry keys instead.
If you're interested you can download a zip file (needed to include the graphics files for the check mark and red x from my OneDrive here.

Sublime Text causing PowerShell script to fail

I have been using SublimeText for a while now and haven't had any issues until recently. Every now and again if I write a PowerShell script in sublime text, the script will fail to run with generic errors such as:
Missing closing '}' in statement block or type definition.
At C:\Users\user\OneDrive\Scripts\~Projects\TRIS-AzureMigration\TRIS-AzureMigration.ps1:7 char:25
+ function Get-SQLInstall {
These errors only show if I call the script from PowerShell. If I copy the script to the console it works. If I run it in ISE it works. I can also run it if I copy the code to notepad and then save it as a .ps1 from there, this tells me that it is something to do with sublime text.
I have had a look around and found a few examples:
My script runs in powershell ISE but not powershell console? :: solution was to copy to a new file, which i dont want to have to do every time.
Any help on this would be much appreciated.
The code block of code that for the error above:
function Get-SQLInstall {
param ( [parameter(Mandatory=$false)]$GetMax = $true)
$instances = #();
$inst = (get-itemproperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server').InstalledInstances;
foreach ($i in $inst)
{
$p = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL').$i;
[version]$v = ((Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$p\Setup").Edition).Major;
$instances += New-Object –TypeName PSObject -Property #{
Edition = ((Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$p\Setup").Edition);
version = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$p\Setup").Version;
SQLPath = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$p\Setup").SqlPath;
SQLFullPath = ((Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$p\Setup").SqlPath) + "\" + [string]$v.major + "0";
}
}
if ($GetMax -eq $true) {
## Get latest SQL version
$max = ($instances | measure-object -Property version -maximum).maximum;
return #($instances | ? { $_.version -eq $max})[0];
}
else {
return $instances;
}
}

Missing AD module and can't get it, need something similar or something to simulate it

So I'm trying to output a complete KB list for all computers on a server (which works on one computer) but it doesn't recognize Get-ADcomputer as a cmdlet. When checking various sources, it appears that the AD module isn't included. As I'm doing this on a work computer/server I'm hesitant to download anything or anything of that nature.
Is there any way I can achieve the following without using the AD module or someway I might be missing how to import the module (if it exists, which I don't think it does on this system)?
# 1. Define credentials
$cred = Get-Credential
# 2. Define a scriptblock
$sb = {
$Session = New-Object -ComObject Microsoft.Update.Session
$Searcher = $Session.CreateUpdateSearcher()
$HistoryCount = $Searcher.GetTotalHistoryCount()
$Searcher.QueryHistory(0,$HistoryCount) | ForEach-Object -Process {
$Title = $null
if ($_.Title -match "\(KB\d{6,7}\)") {
# Split returns an array of strings
$Title = ($_.Title -split '.*\((?<KB>KB\d{6,7})\)')[1]
} else {
$Title = $_.Title
}
$Result = $null
switch ($_.ResultCode) {
0 { $Result = 'NotStarted'}
1 { $Result = 'InProgress' }
2 { $Result = 'Succeeded' }
3 { $Result = 'SucceededWithErrors' }
4 { $Result = 'Failed' }
5 { $Result = 'Aborted' }
default { $Result = $_ }
}
New-Object -TypeName PSObject -Property #{
InstalledOn = Get-Date -Date $_.Date;
Title = $Title;
Name = $_.Title;
Status = $Result
}
} | Sort-Object -Descending:$false -Property InstalledOn | Where {
$_.Title -notmatch "^Definition\sUpdate"
}
}
#Get all servers in your AD (if less than 10000)
Get-ADComputer -ResultPageSize 10000 -SearchScope Subtree -Filter {
(OperatingSystem -like "Windows*Server*")
} | ForEach-Object {
# Get the computername from the AD object
$computer = $_.Name
# Create a hash table for splatting
$HT = #{
ComputerName = $computer ;
ScriptBlock = $sb ;
Credential = $cred;
ErrorAction = "Stop";
}
# Execute the code on remote computers
try {
Invoke-Command #HT
} catch {
Write-Warning -Message "Failed to execute on $computer because $($_.Exception.Message)"
}
} | Format-Table PSComputerName,Title,Status,InstalledOn,Name -AutoSize
You've got 3 options:
First is to just install the RSAT feature for AD which will include the AD module. This is probably the best option unless there is something specific preventing it. If you're running your script from a client operating systems you need to install the RSAT first, though.
Option 2 (which should only be used if adding the Windows feature is somehow an issue) is to download and use the Quest AD tools, which give very similar functionality, but it looks like Dell is doing their best to hide these now so that may be difficult to locate...
Option 3 is to use the .NET ADSI classes to access AD directly, which will work without any additional downloads on any system capable of running PowerShell. If you'd like to go this route you should check out the documentation for the interface Here and for the System.DirectoryServices namespace Here.
Edit
Just noticed the last part of your question, what do you mean by "a complete KB list"? Not just Windows updates or things updated manually or whatever? What else would be in a list of Windows updates that was not a Windows update?
You have not mentioned the OSes you are using but in general if you have a server 2008 R2 or above, all you have to do it activate the RSAT feature AD PowerShell Module and you will have the cmdlet you are looking for.
On a client machine, you 'have to' install RSAT, and then activate the features. You can take a look at the technet article for more info: https://technet.microsoft.com/en-us/library/ee449483(v=ws.10).aspx
If you don't want to use that option, then you will have to use .NET ADSI classes. There are tons of examples on how to do this, it basically boils down to a couple of lines really. Technet has examples on this as well: https://technet.microsoft.com/en-us/library/ff730967.aspx