Powershell last bootup time of computer showing two different outputs - powershell

$OSInfo = get-wmiobject -class win32_operatingsystem -computername c83323
($OSInfo `
| Format-List `
#{Name="OS Boot Time";Expression={$_.ConvertToDateTime($_.LastBootUpTime)}} `
| Out-String).Trim() #Output OS Name, Boot Time, and Install Date
output --> OS Boot Time : 12/6/2016 4:09:20 PM
$osinfo = get-wmiobject -class win32_operatingsystem -computername c83323
$osinfo.ConvertToDateTime($osinfo.LastBootUpTime)
output --> Tuesday, December 06, 2016 4:09:20 PM
Why is it when I run the first set, I get time in one way, but when I run it the 2nd way, I get it in a completely different format?

This is because you are using Format-List and/or Out-String in the first case. When using these, PowerShell formats the DateTime object's output, just as if you wrote this:
"$(Get-Date)"

The output of your second instance will be in DateTime type. This format depends on the datetime format you have Choosen on your system.
I modified your code to get the type:
$osinfo = get-wmiobject -class win32_operatingsystem; ($osinfo.ConvertToDateTime($osinfo.LastBootUpTime)).GetType()
But in your first instance, you use something called a calculated property (check this link) , which basically let you "Format" and display attributes in the way you prefer. In your case, thru the expression you have provided your date and time had converted into an array and hence it lost its format.
Get type:
($OSInfo | Format-List #{Name="OS Boot Time";Expression={$_.ConvertToDateTime($_.LastBootUpTime)}}).GetType()
The above type would be an array.
EDIT:
Below snippet should do the trick!
#("Computer1","Computer2") | foreach {
$OSInfo = get-wmiobject -class win32_operatingsystem -computername $_;
"Boot time for Computer: $_ = " + $OSInfo.ConvertToDateTime($OSInfo.LastBootUpTime);
} | Out-File "C:\thefolderYouPrefer\boottime.txt"

Related

Powershell - how to replace OS Version number with String

I am querying remote servers for their operating system. I know that I can return the Version, but I want to replace these values with the friendly name. The code I have so far is:
$Computer = (gc c:\servers.txt)
$BuildVersion = Get-WmiObject -Class Win32_OperatingSystem -Property Version, CSName -ComputerName $Computer -ErrorAction SilentlyContinue
$Build=$BuildVersion.version
If ({$BuildVersion.Version -match "5.2.3790"})
{$Build="2003"}
Elseif ({$BuildVersion.Version -match "6.1.7601"})
{$Build="2008"}
Elseif ({$BuildVersion.Version -like "6.3.9600"})
{$Build="2012"}
But this doesn't seem to work and only returns "2003" regardless. Please help, I'm fairly new to PS and coding.
thanks
The problem is your if statements. Putting the Boolean expression inside squiggly brackets makes it a script block, and that's going to get cast as a string before being cast as a Boolean. Strings cast to Booleans always evaluate to true unless they're empty.
PS C:\> {$BuildVersion.Version -match "5.2.3790"}
$BuildVersion.Version -match "5.2.3790"
PS C:\> ({$BuildVersion.Version -match "5.2.3790"}) -as [bool]
True
PS C:\> $BuildVersion.Version -match "5.2.3790"
False
PS C:\> ($BuildVersion.Version -match "5.2.3790") -as [bool]
False
So what you're running is essentially:
if ([bool]'$BuildVersion.Version -match "5.2.3790"') [...]
And that's always going to be true.
Try:
$Computer = (gc c:\servers.txt)
$BuildVersion = Get-WmiObject -Class Win32_OperatingSystem -Property Version, CSName -ComputerName $Computer -ErrorAction SilentlyContinue
$Build=$BuildVersion.version
If ($BuildVersion.Version -match "5.2.3790")
{
$Build = "2003"
}
Elseif ($BuildVersion.Version -match "6.1.7601")
{
$Build = "2008"
}
Elseif ($BuildVersion.Version -like "6.3.9600")
{
$Build = "2012"
}
Bottom line is that squiggly brackets are not parentheses and you can't use them like they are.
However, there's also a major logic error here. You're potentially fetching an array for $BuildVersion because you're reading from a file, but then you treat it like a single value. You never loop through $BuildVersion. However, I do not have enough information about what you're actually trying to do with your script (like what you do with $Build) to be able to fix that.
I originally said this, but I've since changed my mind
The reason this is only returning 2003 is that you're only running your If code on a single entry in the list.
Wrong
As TessellatingHeckler says, the reason your if wasn't working is that you had too many curly braces, so PowerShell wasn't actually evaluating your logic.
However, you still need to step through each of the computers to do what you're trying to do. We'll do that by adding in a ForEach loop. I also went ahead and replaced your If {} logic with a Switch statement, which I think is easier to understand for a scenario like this with multiple clauses. If's just get way too verbose.
Finally, I'm assuming you want to output the results too, so I added a custom object here, which is just a way of choosing which properties we want to display.
$Computer = (gc c:\servers.txt)
ForEach ($system in $computer){
$BuildVersion = Get-WmiObject -Class Win32_OperatingSystem -Property Version, CSName -ComputerName $system -ErrorAction SilentlyContinue
$Build=$BuildVersion.version
switch ($build){
"5.2.3790" {$Build="2003"}
"6.1.7601" {$Build="2008"}
"6.3.9600" {$Build="2012"}
}
#output results
[pscustomobject]#{Server=$system;OSVersion=$build;CSName=$buildVersion.CSname}
}#EndOfForEach
Output
>Server OSVersion CSName
------ --------- ------
dc2012 2012 DC2012
sccm1511 2012 SCCM1511
You can use this:
Get-WmiObject -Class Win32_OperatingSystem | Select-Object -ExpandProperty Caption
Additionally you can see everything this WMI object holds like this:
Get-WmiObject -Class Win32_OperatingSystem | fl *
Edit: if you want to remove some text from the string, you can use -replace:
(Get-WmiObject -Class Win32_OperatingSystem |
Select-Object -ExpandProperty Caption) -replace "Microsoft Windows Server ",""

converting datetime from wmiobject to datetime

Trying to get the difference in days between to dates: Today's date. and a date/time from a wmiobject (this was taken from a post from the PendingReboot script from Hey, Scripting! blog):
$Lastreboottime = Get-WmiObject win32_operatingsystem -ComputerName $Computer |
select csname, #{LABEL='LastBootUpTime';EXPRESSION=$_.ConverttoDateTime($_.lastbootuptime)}}
$Today = Get-Date -Format d
$DiffDays = $Today - $Lastreboottime
The result of $Today is
09/06/2016
and $Lastreboottime is
05/05/2016 11:13:21
So I want to get rid of the time but not sure how to do this.
Secondly, I get this error if I were to run the script, though I guess this may go away if I am able to extract the date only in $Lastreboot
Cannot convert the "#{csname=JDWTAWEB1; LastBootUpTime=05/05/2016 11:13:21}" value of type "Selected.System.Management.ManagementObject" to type "System.DateTime".
Any ideas?
Remove -Format d and compare the Date-properties of the DateTime-objects to get the days-diff only.
Your $Lastreboottime-variable references an object with both computername csname and the LastBootUpTime, so you need to access the LastBootUpTime
Try:
$Lastreboottime = Get-WmiObject win32_operatingsystem |
select csname, #{LABEL='LastBootUpTime';EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}}
$Today = Get-Date
$DiffDays = $Today.Date - $Lastreboottime.LastBootUpTime.Date
$DiffDays.TotalDays
13
I think that the WMIObject conversion might need to get to a Datetime object by way of a properly formatted string. I did this (minus the -Computername $Computer part) and it seemed to work.
[string]$BootTimeString=(Get-WmiObject win32_operatingsystem -ComputerName $Computer).lastbootuptime -replace '\..*',''
$BootTimeDT=[datetime]::ParseExact($BootTimeString,'yyyyMMddHHmmss',$null)
$DiffDays = (NEW-TIMESPAN –Start $BootTimeDT –End (Get-Date)).Days
Remove -Format d from Get-Date. You need DateTime object, not a string.
$Lastreboottime is an object with 2 properties: csname and lastbootuptime. You have to use lastbootuptime property.
Example:
$Today = Get-Date
$DiffDays = $Today - $Lastreboottime.lastbootuptime

PowerShell and CSV

I'm working on script which collects information about computer (os version, software installed etc.) and I would like to get output in CSV file to be able to import in SQL later.
Currently, I have something like this:
$os = Get-WmiObject Win32_OperatingSystem
$soft = Get-WmiObject Win32_Product
$customerid = $env:UserName
$osversion = $os.Caption
$osplatform = $os.OSArchitecture
$ossp = $os.servicepackmajorversion
$timestamp = Get-Date -Format "dd.MM.yyyy HH:mm"
$timestamp,$customerid, $osversion, $osplatform, $ossp, $soft.Name, $soft.Version | Out-File C:\test.csv
I would prefer output file something like this:
http://s9.postimg.org/5zmwoda4f/image.png
but at the moment I'm gettting all information this way:
http://s12.postimg.org/9gsrvdfz1/image.png
How can I achieve output like in the first image?
Thank you for any help!
What you are seeing is how the pipe is dealing with arrays. To get the output you desire we need to make some other changes since you didn't make any effort to add titles and what not. This output deviates slightly from what you desire since it is easier to have the software title on its own line.
$os = Get-WmiObject Win32_OperatingSystem
$soft = Get-WmiObject Win32_Product
$customerid = $env:UserName
$osversion = $os.Caption
$osplatform = $os.OSArchitecture
$ossp = $os.servicepackmajorversion
$timestamp = Get-Date -Format "dd.MM.yyyy HH:mm"
$softwareDetails = ($soft | ForEach-Object{",$($_.Name),,,,,$($_.Version)"})
"Time:,$timestamp",
"UserName:,$customerid",
"OS Version,$osversion",
"Architecture,$osplatform",
"Service Pack,$ossp",
"Software Versions",
$softwareDetails | Out-File C:\test.csv
Since we are using arrays for output each entry will be on it's own line. I would have suggested using Export-CSV but your desired output does not match a traditional csv file.

Full output hidden on console

I don't get full output of the following code I made.
For Example:
DriveSpace : {174, 0, 98, 171...}
Notice the ellipses (...) after 171. It is skipping the rest of the output after that. You can run the following script to see my output.
#Start of script
$cpu = gwmi -Class Win32_Processor | Select-Object NumberOfCores,NumberOfLogicalProcessors
$memory = gwmi -class win32_physicalmemory | Select-Object {[math]::truncate($_.capacity / 1GB)}
$HostDescription= gwmi -Class Win32_OperatingSystem
$fqdn = "$env:computername.$env:userdnsdomain"
$OS = (gwmi Win32_OperatingSystem)
$OSarchitecture = (gwmi Win32_OperatingSystem)
$disk = gwmi Win32_LogicalDisk | Select-Object DeviceID, volumeName, {[math]::truncate($_.size / 1GB)}
$timezone = [System.TimeZone]::CurrentTimeZone
$fire = netsh advfirewall show publicprofile | select-string state
$firematch = $fire -match "off"
$slmgrResult = cscript c:\windows\system32\slmgr.vbs /dli | Select-string "License Status"
$activation = $slmgrResult -match "Licensed"
$apps = gp HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |Select DisplayName, DisplayVersion, Publisher, InstallDate
$network = Get-WmiObject win32_networkadapterconfiguration -filter "ipenabled = 'True'" | select-object IPAddress, DefaultIPGateway, DNSDomain, IPSubnet
$props = #{
NumberOfCores = $cpu.NumberOfCores
NumberOfLogicalProcessors = $cpu.NumberOfLogicalProcessors
Memory = $memory.{[math]::truncate($_.capacity / 1GB)}
HostDescription = $HostDescription.Description
FQDN = "$env:computername.$env:userdnsdomain"
OS = (gwmi Win32_OperatingSystem).Name
OSarchitecture = $OSarchitecture.OSArchitecture
DriveLetters = $disk.DeviceID
DriveLabels = $disk.volumeName
DriveSpace = $disk.{[math]::truncate($_.size / 1GB)}
timezone = [System.TimeZone]::CurrentTimeZone.StandardName
FirewallDisabled = $firematch
Licensed = $activation
Applications = $apps
IPAddress_Gateway_DNSDomain_subnet = $network.IPAddress, $network.DefaultIPGateway, $network.DNSDomain, $network.IPSubnet
}
New-Object PSObject -Property $props
#End of script
This is not an official answer as I think the OP needs to be clear on what output he is expecting. This is a start nonetheless
While I have not found official documentation to support this you are just seeing how PowerShell handles console output. Consider the following example which is a collection of varying sizes of arrays.
[pscustomobject]#{
data = "1","2","3","4","5"
}
Would produce the following list style output.
data : {1, 2, 3, 4...}
Notice the fifth element of the 5 property now has the ellipses. The data is still there. It has just been truncated on the console to make the output more terse and easier to read. In this case it seems folly to do so but with some objects complicated output PowerShell has to draw the line somewhere.
Prevent the ellipses
As PetSerAL pointed out you can just use the following line of code before your output.
$FormatEnumerationLimit=-1
If you look at about_Preference_Variables you will see that, by default, this is set to 4. That would support the output you are seeing. Set that value to something higher or -1 and see if it helps.
Other Potential Issues
Like in my comments I want to draw attention to the variable you created called $disk. The output is below. Note this is from my own machine and wont match yours. Still, you should get the picture
DeviceID volumeName [math]::truncate($_.size / 1GB)
-------- ---------- -------------------------------
C: 111
D: Data 499
E: Multimedia 1362
F: 0
G: CentOS 7 x86_64 3
M: Media 2794
Z: 0
Without any other information I can only assume that you want a series of free space values to display. Given that we could break those results out of the array by casting them to string. Also want to update the line that populates the variable.
$disk = gwmi Win32_LogicalDisk | Select-Object DeviceID, volumeName, #{Label="Size(GB)";Expression={[math]::truncate($_.size / 1GB)}}
Gives us the following in $disk`
DeviceID volumeName Size(GB)
-------- ---------- --------
C: 111
D: Data 499
E: Multimedia 1362
F: 0
G: CentOS 7 x86_64 3
M: Media 2794
Z: 0
Then when you build your hashtable you can cast the array to a single space delimited string like this:
DriveSpace = [string]($disk."Size(GB)")
Fairly sure there will be more questions to come from this but it is at least a start. Welcome to SO. It is always a good idea when possible to show us desired output in cases like this so we know what you are trying to achieve. Even if you think it is obvious.
Side notes
You have other properties other that $disk that might have the same issues like Applications which is a complex object. If you do have issues with those as well solving this one might get you in the right direction.
You have many calls to gwmi Win32_OperatingSystem. You should save the results of that into a variable that you can refer to whenever you need it. Right now you are losing time calling it and getting the same results. For example:
$wmiOS = gwmi Win32_OperatingSystem
This is the default formatting of Powershell at work, as provided by Out-Default. It is truncating the DriveSpace array to display in a table in your console, but the information is still there. For example, if you type:
$props.DriveSpace
... you will see the full array displayed. The default formatting behaves differently when it's handling a simple array as opposed to when it's handling a complex object like the $props one you've created.
See also:
How Powershell Outputting and Formatting REALLY works

Powershell ConvertToDateTime() Method and Get-WMiObject

I am generating a report in PS and everything works fine, but when I try to use ConvertToDateTime to make the date readable it comes out blank? But only on Get-WmiObject Win32_Product others like Win32_Operatingsystem seem to come out fine.
$Install = #{n="Installed";e={$_.ConvertToDateTime($_.InstallDate)}}
$frag14 = Get-WmiObject Win32_Product -ComputerName $name | Select Name,Version,PackageName,$Install,Vendor | Sort Name |
ConvertTo-html -Fragment
InstallDate is just a string, it's a CIM based date string. Try this:
$Install = #{n="Installed";e={[DateTime]::ParseExact($_.InstallDate,'yyyyMMdd',$null)}}
You will not get install date in win32_product class, it is a known bug.
According to the class definition of Win32_Product see MSDN InstallDate is a just a string, not a CIM based string. The string contains a date like format yyyyMMdd, ie "20170417". InstallDate2 is a CIM base datetime string. Specifically, it is a CIM_DateTime datatype which should contain a value in this format yyyymmddHHMMSS.mmmmmmsUUU where sUUU is time zone offset in minutes. ie 20170417101205.000000-420.
This Win32_Product class is recommended to vendors to populate, but sadly InstallDate2 is not required and generally always empty. Partial definition of Win32_Product class from MSDN.
class Win32_Product : CIM_Product
{ uint16 AssignmentType;
string Caption;
string Description;
string IdentifyingNumber;
string InstallDate;
datetime InstallDate2;
...
The following Powershell command lists all of your installed products with install dates (warning very slow).
Get-WmiObject -Class Win32_Product | Select-Object -Property Name, InstallDate, InstallDate2